There have been multiple options of using running numbers and as developers we have used options of IDENTITY in the past. With SQL Server 2012, there is an interesting option to utilize called as SEQUENCE. I am not sure how many of you are using this new feature in your applications already. In this post wanted to quickly give you some ways to use this nice little addition into SQL Server.
The syntax for SEQUENCE can be got from the documentation mentioned above. Let us create a simple table and Sequence to start with for our experiment.
In the above script the important part is the last command where we initialize the SEQUENCE. What we created is:
Data type: BIGINT
Starts at 1 which is greater than minvalue and less than maxvalue
MaxValue is max value of the type i.e. 9223372036854775807
MinValue is min value of the type i.e. -9223372036854775808
Increment is 1 – can also be negative.
No cycle – means it will error after maxvalue
Cache is used, database engine will select a size and selection might not be consistent.
‘CREATE SEQUENCE’ does not allow specifying the database name as a prefix to the object name.
Only word of caution is wrt cache. Using of cache can minimize some IO at generation time, but at the same time if any abrupt crash or power outage can mean the cache values can be lost and there can be breakage in the sequence values.
Get the SEQUENCE Metadata from inside SQL Server. Use the sys.sequence DMV for this task.
This confirms our initial understanding of the values and how they can be queried from the system. This DMV can be used to see what SEQUENCEs have been defined inside a Database.
Generating sequence numbers is a simple step using the “next value” construct.
Since we are using the GO 10, there are 10 sequence numbers that get generated.
Quick Quiz: What will be the output from the below query if I run them now.
Will the values be:
- None of the above
Please post the answer over comments and would love to see your explanation for the same too. For correct answers, we will send you Pluralsight Codes to watch our courses.
Let us next, alter an existing SEQUENCE number to different values:
Only catch here is: Data type can’t be changed by alter statement. And “START WITH” cannot be used in an ALTER SEQUENCE command.
Given this constrain, decide on if you want to go with smallint, int, bigint or decimals/numeric (with 0 scale). I would suggest the choice would be between int and bigint – not to forget the storage or memory needs from a cache. Given these days few MB’s is fine from an overhead when the world is moving to TB’s of data :).
Using SEQUENCE Inside Transactions
The next aspect is to use the SEQUENCE values inside a transaction and see how they get affected. Use the below status check query to keep a tap on the progress every step.
Let us start by using an implicit transaction inside SSMS and insert one value. The output of the same is:
This seems to be one of the easiest of steps. Now if we use an Explicit transaction and if we rollback, how would the SEQUENCE Status look like?
Now you can see that the values as part of INSERT have been rolled back, yet there is a small difference in the status check – the current value is 11. This confirms that the SEQUENCE has jumped to the next value and doesn’t participate as part of transaction rollback. This is the same / similar behavior to how IDENTITY works inside SQL too. Hence if we insert a new row, it would have skipped a value of 11 as we gave a increment of 10 in the last alter statement.
It is sort of different from IDENTITY because even the IDENTITY can get reset using the TRUNCATE command, but SEQUENCE has to be reinitialized using the ALTER for the same.
Getting a range of values
Now that we are talking about sequences, there have been requirements to get a range of values. The same can be achieved using a stored procedure – sp_sequence_get_range. The idea here would be an application might need some range of values it can use from the sequence generated from the backend. In case of pessimistic locking lot of people ask me is it possible to know the IDENTITY before we insert so that they can send the parent and child (with foreign key populated) in one shot into SQL Server. Here is a typical way to achieve that.
Let me add the command text used above for easy access.
DECLARE @sequence_name nvarchar(100) = ‘SequenceID’, @range_size int = 10,
@range_first_value sql_variant, @range_last_value sql_variant,
@range_cycle_count int, @sequence_increment sql_variant,
@sequence_min_value sql_variant, @sequence_max_value sql_variant;
EXEC sp_sequence_get_range @sequence_name = @sequence_name, @range_size = @range_size,
@range_first_value = @range_first_value output, @range_last_value = @range_last_value output,
@range_cycle_count = @range_cycle_count output, @sequence_increment = @sequence_increment output,
@sequence_min_value = @sequence_min_value output, @sequence_max_value = @sequence_max_value output;
SELECT RangeSize= @range_size,FirstValue=@range_first_value,LastValue= @range_last_value,CycleCount=@range_cycle_count,
Increment=@sequence_increment,MinValue= @sequence_min_value,MaxValue= @sequence_max_value;
The documentation is pretty exhaustive and can be helpful for reference– MSDN/BOL.
There are a number of ways to use SEQUENCE inside SQL Server. We have already seen how one might use the same inside a SELECT (Option 1) or INSERT Statement (Option 2) above. Let me give you some other options of how one might use SEQUENCE.
Option 3 – Pre-generation and Batching
Get the next value before inserting. If you have not taken the quiz / trivia above – do that. You will realize that the solution for that question is by doing a batch operation like one written below. Unlike in the previous case, all expressions that appear in the same logical query processing phase are evaluated as if at the same point in time hence giving it a batch window eliminates that problem.
Option 4 – OVER and Order by
This will be one of the common methods people might start using the SEQUENCEs. Your requirement is to get some sequence or order while you get the resultset and this can be yet another way to use. You can use the overall ranking functions also to get two numbered set one as a master and other as a subset ranking set. A typical example is:
Option 5 – Using inside Update statement
There can be a requirement you want to create some running sequence for an already existing values inside SQL Server as part of migrating it to SQL Server 2012. Also you don’t want any breaks in that sequence (like Invoice etc). You can use this technique to generate such running numbers and then reset / reseed if you are using the identity columns. If you get the drift then you can easily build the script using another column and achieve the same. Though I did this for one of the ISV’s keep in mind the Foreign key pitfalls as part of the activity.
Option 6 – Use it via DEFAULT Column value
This option is a great way to use in comparison to IDENTITY values. Some of the benefits of cache can surely eliminate the contention on the last page because of IDENTITY value generation. And I see this as a new way to maintain and create unique numbers inside SQL Server. In the example below, the default constraint makes sure the next value has been entered and see the entry of last 8th row automatically.
Why SEQUENCE when IDENTITY is there?
UPDATE: A lot of people are asking when to use sequence and when IDENTITY. The scenario is simple, if you need a unique sequence number to be generated across a single database then sequence can be of great help. IDENTITY can be used to generate a unique number for a given table and not across tables. That is the fundamental difference between both.
Though SEQUENCE can also be used to replace IDENTITY in the future, given the caching and faster retrieval, this is an option to explore and use. I would say, do a simple performance testing to know which one performs better. You will surely surprised :).
Your question in mind is – is it a replacement for IDENTITY? Well, it can be as one of the options. Do a small performance test to see which of these methods fair well for use before doing the replacement. I have seen acceptable performance with SEQUENCE usage on a decent workload – but you are better judge of the final results in your environments.
As time permits, feel free to pass me your comments.