SQL Server 的自定义序列

Tib*_*mas 2 replication sql-server auto-increment sequence identity

使用 SQL Server 生成自定义自动生成序列的最佳方法是什么?

这是我的要求:

  • 我的应用程序托管在 10 台未互连的独立服务器上。

  • 每个实例都应该生成一个序列号,所有这些数据将使用 SQL Server 的合并复制合并到所有数据库中。

  • 生成的序列在所有服务器中应该是唯一的。

为了实现这一点,我创建了一个函数来为序列号添加服务器 id 前缀,并将其用作计算列。但是当我添加数据时,出现以下异常:

“已超出最大存储过程、函数、触发器或视图嵌套级别(限制为 32)。”

这是我的表和函数。请提出更好的方法。

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()
Run Code Online (Sandbox Code Playgroud)

Joh*_*ner 5

为什么不直接使用SEQUENCE2012 年引入 SQL Server的实际值?

以下方法重载了BIGINT值,其中前 10 位数字表示转换为 a 后的服务器 IP 地址BIGINT(通过SQLDenis在这篇博文中概述的方法),最右边的 10 位数字表示实例本地的 CustomerID。ABIGINT最多可以有 19 位数字,但因为最左边的数字永远不会高于4序列的开始,这允许比 anINT允许的最大值多得多的客户编号(代码中的注释在再详细一点)。

这种方法的唯一要求是此解决方案最多只能部署到每个服务器一个实例(因为 IP 在同一服务器上托管的实例之间不会是唯一的)。如上所述,这种方法仍然允许INT您的解决方案中的每个实例最多 2,147,483,647 个客户。因为CID表中的列在INT您的问题中被定义为 a ,所以我假设这是可以接受的。它仍然与您在其他任何地方找到的方法一样快。

-- This sequence will have a dynamic starting number **PER SERVER** based on IP
-- Max value for BigINT is 9,223,372,036,854,775,807
-- Max value for INT is                2,147,483,647
-- Max IP (255.255.255.255) to BIGINT: 4,294,967,295
-- IP to padded BIGINT:    4,294,967,295
--                       *             1,000,000,000
--                       ---------------------------
-- Max Starting Value =    4,294,967,295,000,000,000

-- Variables to capture server id (IP) and generate sequence DDL statement
DECLARE @serverid BIGINT, @sequenceDSQL VARCHAR(4000)

-- Convert IP to BIGINT
SELECT TOP(1) @serverid =
        (CONVERT(bigint, PARSENAME(local_net_address,1)) +
         CONVERT(bigint, PARSENAME(local_net_address,2)) * 256 +
         CONVERT(bigint, PARSENAME(local_net_address,3)) * 65536 +
         CONVERT(bigint, PARSENAME(local_net_address,4)) * 16777216)
FROM sys.dm_exec_connections AS c
WHERE c.local_net_address IS NOT NULL;

-- Shift Server IP value to left of the BIGINT value
SET @serverid = @serverid * 1000000000

-- Generate Dynamic SQL DDL for CREATE SEQUENCE Statement
SET @sequenceDSQL = '
CREATE SEQUENCE dbo.NextCustomerNumber
AS BIGINT
    START WITH ' + CAST(@serverid AS VARCHAR(19)) + '
    INCREMENT BY 1
    NO MAXVALUE
    NO CACHE -- Or switch to CACHE if you''re seeing performance issues on inserts'

-- Create the Sequence
EXEC(@sequenceDSQL)

-- Create the Table
create table dbo.Customers
(
    CID int identity not null primary key,
    CustomerName varchar(50),
    CustomerNumber bigint DEFAULT (NEXT VALUE FOR dbo.NextCustomerNumber)
)
GO
Run Code Online (Sandbox Code Playgroud)

如果您还想考虑该@serverid值的端口号,您将达到 aBIGINT可以容纳的限制,因此我建议为服务器提供除 IP/端口以外的其他一些唯一标识符。但是,我的代码应该显示一种通用方法,您可以根据需要进行调整以解决您的问题。