Sql server 2022自增ID在重启后不连续,出现跳跃怎么办?

BKT 发表于 - 3 分钟阅读 - 1035 个字

从 SQL Server 2012 版本开始,微软引入了 Identity Cache 功能,当重新启动 SQL Server 实例时,其自动标识列值将根据标识列数据类型跳转。

介绍

从 SQL Server 2012 版本开始,当重新启动 SQL Server 实例时,表的Identity 值会跳转,实际跳转的值取决于标识列数据类型。如果是整数 ( int) 数据类型,则跳转值为1000 ,如果是大整数 ( bigint),则跳转值为10000。从我们的应用程序的角度来看,这种增量对于所有业务案例都是不可接受的,特别是当值显示给客户端时。这是仅随 SQL Server 2012 附带的特殊情况/问题,旧版本没有这样的问题。

背景

几天前,我们的 QA 工程师声称我们的一个表的标识列跳变了10000。这意味着该表的最后一个标识值2200 现在是12001。在我们的业务逻辑中,该值显示给客户端,但客户端不会接受。所以我们必须解决这个问题。

使用代码

第一次,我们都感到惊讶和困惑,这怎么可能?我们通常不会在标识列中插入任何值(可以向标识列插入值)。标识值由 SQL Server 本身维护。我们团队的一名核心成员开始调查这个问题并找到了解决方案。现在,我想详细说明我的同事发现的问题和解决方案。

如何重现?

您需要设置 SQL Server 2012 并创建一个测试数据库。然后创建一个带有自动标识列的表:

create table MyTestTable(Id int Identity(1,1), Name varchar(255));

现在在那里插入两行:

insert into MyTestTable(Name) values ('Mr.Tom');
insert into MyTestTable(Name) values ('Mr.Jackson'); 

你会看到结果:

SELECT Id, Name FROM MyTestTable; 

结果与预期一致。现在只需重新启动 SQL Server 服务即可。有多种方法可以做到这一点。我们是通过 SQL Server 管理工作室完成的。

现在,再次向同一张表中插入另外两行:

insert into MyTestTable(Name) values ('Mr.Tom2');
insert into MyTestTable(Name) values ('Mr.Jackson2');

现在看看结果:

SELECT Id, Name FROM MyTestTable;

ID-Jump

现在你看到,重新启动 SQL Server 2012 实例后,标识值以 开头1002。这意味着它跳了1000。之前,我说过,我们还会看到,如果该标识列的数据类型是bigint,那么它将跳转10000。

这真是个 bug 吗?

微软宣称这是一个功能而不是一个错误,在许多情况下它会很有帮助。但在我们的例子中,这是不可接受的,因为该数字会显示给客户端,客户端会在跳转后惊讶地看到这个新数字,而新数字取决于 SQL Server 重新启动的次数。如果客户端看不到它,那么它可能是可以接受的,以便该数字在内部使用。

解决方案

如果我们对这个所谓的功能不感兴趣,那么我们可以做两件事来阻止这种跳跃。

  1. 在数据库级别禁用 IDENTITY CACHE 选项

在 SQL Server 中,IDENTITY CACHE 的默认配置值将针对每个用户数据库级别设置为“ON”。从根本上讲,IDENTITY CACHE 是一种提高插入操作性能的功能。但是,可以在数据库级别禁用它,以避免表列中出现身份差距。

USE DatabaseName
GO
ALTER DATABASE SCOPED CONFIGURATION SET IDENTITY_CACHE = OFF
GO
  1. 将 -t272 注册到 SQL Server 启动参数(在 SQL Server 实例级别禁用 IDENTITY CACHE)

sql-server-id-jump-t272

相关内容:

https://www.sqlshack.com/learn-to-avoid-an-identity-jump-issue-identity_cache-with-the-help-of-trace-command-t272/

https://www.codeproject.com/Tips/668042/SQL-Server-2012-Auto-Identity-Column-Value-Jump-Is

comments powered by Disqus