SQL Server 2016序列生成ID出现80-100跳号的排查与复现咨询
SQL Server 2016 Sequence 80-100跳号问题:原因与复现方法
一、跳号核心原因
当前调用存储过程时固定@increment=1,走直接执行NEXT VALUE FOR [序列名]的逻辑,跳号的主要诱因是SQL Server Sequence的缓存机制:
- Sequence默认启用缓存(默认缓存大小为50),若创建序列时显式指定更大的缓存值(比如
CACHE 100),实例会一次性预加载一批序列值到内存,供后续请求快速获取。 - 当SQL Server服务重启、承载序列缓存的进程异常终止,或通过
sp_sequence_get_range获取的序列范围未被实际使用(比如事务回滚),缓存中未消耗的序列值会被直接丢弃,后续请求会从下一个缓存块的起始值开始,从而产生80-100的间隙。
另外,若存在其他业务场景调用该存储过程时传入较大的@increment值(比如100),即使事务回滚,sp_sequence_get_range获取的整个序列范围也会被标记为已使用,同样会造成大范围跳号。
二、复现方法
场景1:服务重启触发缓存丢失
- 创建带100大小缓存的序列(匹配跳号范围):
CREATE SEQUENCE dbo.n_TestTable AS BIGINT START WITH 1 INCREMENT BY 1 CACHE 100;
- 调用存储过程
axsp_get_next_no_internal_64,传入@table_name='TestTable'、@increment=1等参数,连续调用10次,得到序列值1-10。 - 重启SQL Server服务。
- 再次调用存储过程,获取到的下一个值为101,中间11-100的间隙完全匹配用户遇到的跳号现象。
场景2:sp_sequence_get_range未使用序列范围触发跳号
- 使用上述序列,打开新会话执行:
DECLARE @new_no BIGINT; EXEC dbo.axsp_get_next_no_internal_64 @table_name='TestTable', @increment=100, @is_use_sequence=1, @new_next_no=@new_no OUTPUT; -- 此时@new_no为101,序列已预占1-100范围 ROLLBACK; -- 模拟事务回滚,未实际使用该范围
- 回到正常调用逻辑,传入
@increment=1调用存储过程,获取到的下一个值为101,中间1-100的序列值已被消耗且未被使用,形成间隙。
场景3:会话异常终止(实例级缓存场景)
- 保持序列缓存为100,打开一个会话,执行多次
NEXT VALUE FOR dbo.n_TestTable,获取到1-5。 - 强制终止该会话(比如关闭SSMS窗口、执行
KILL [会话ID])。 - 若SQL Server实例回收了该缓存块(极端场景),后续调用存储过程会直接加载下一批缓存(101-200),导致11-100的间隙。
三、关键结论
SQL Server Sequence的设计目标是高性能生成唯一值,而非保证序列连续。缓存机制是性能优化的核心,但也是大范围跳号的主要来源。即使无异常场景,事务回滚也会导致单个或少量跳号,缓存丢失则会引发批量跳号。
内容的提问来源于stack exchange,提问作者Mayur
相关产品推荐
相关产品推荐

