What is the best method to generate a Custom Auto-Generated Sequence with SQL Server?
Here is my requirement:
-
My application is hosted on 10 independent servers which are not
interconnected. -
Each instance should generate a sequence number, and all these data
will be merged to all databases using SQL Server's merge replication. -
The sequence generated should be unique across all the servers.
To achieve this, I have created a function to prefix a server id to the sequence number and used this as a computed column. But when I add data, I am getting the following exception:
"Maximum stored procedure, function, trigger, or view nesting level
exceeded (limit 32)."
Here is my table and function. Kindly suggest a better method.
create table Customers
(
CID int identity not null primary key,
CustomerName varchar(50)
)
ALTER function [dbo].[NextCustomerNumber]()
returns bigint
as
begin
declare @lastval bigint
declare @serverId int
declare @newval bigint
set @lastval = (select max(CustomerNumber) from Customers)
set @serverId= 1 -- Server ID pulls from some settings
set @newval=CONVERT(bigint, (CAST(@serverId as varchar(2))+CONVERT( varchar(10),(RIGHT(@lastval,(LEN(@lastval)-LEN(@serverId)))+1))))
return @newval
end
Alter table Customers add CustomerNumber as dbo.NextCustomerNumber()
Best Answer
Why don't you just use an actual
SEQUENCE
which was introduced to SQL Server with 2012?The following approach overloads the
BIGINT
value where the leading 10 digits represent the server IP address after being converted to aBIGINT
(via the method outlined in this blog post by SQLDenis) and the right-most 10 digits represent the CustomerID local to the instance. ABIGINT
can have up to a maximum of 19 digits, but because the leftmost digit will never be higher than4
to start the sequence this allows for far more customer numbers than the max value of anINT
allows for (the comments in the code explain it in a little more detail).The only requirement for this approach is that this solution only be deployed to, at most, one instance per server (because IP won't be unique across instances hosted on the same server). As stated above, this approach still allows up to the
INT
maximum of 2,147,483,647 customers per instance in your solution. Because theCID
column in the tables is defined as aINT
in your question, I'm assuming this is acceptable. It's still about as fast of an approach as you'll find anywhere else.If you want to also factor in the port number for the
@serverid
value, you're going to reach a limit of what aBIGINT
can hold, so I would suggest coming up with some other unique identifier for the server other than IP/port. However, my code should show a general approach that you can adjust as needed to solve your problem.