从 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;
现在你看到,重新启动 SQL Server 2012 实例后,标识值以 开头1002。这意味着它跳了1000。之前,我说过,我们还会看到,如果该标识列的数据类型是bigint,那么它将跳转10000。
这真是个 bug 吗?
微软宣称这是一个功能而不是一个错误,在许多情况下它会很有帮助。但在我们的例子中,这是不可接受的,因为该数字会显示给客户端,客户端会在跳转后惊讶地看到这个新数字,而新数字取决于 SQL Server 重新启动的次数。如果客户端看不到它,那么它可能是可以接受的,以便该数字在内部使用。
解决方案
如果我们对这个所谓的功能不感兴趣,那么我们可以做两件事来阻止这种跳跃。
- 在数据库级别禁用 IDENTITY CACHE 选项
在 SQL Server 中,IDENTITY CACHE 的默认配置值将针对每个用户数据库级别设置为“ON”。从根本上讲,IDENTITY CACHE 是一种提高插入操作性能的功能。但是,可以在数据库级别禁用它,以避免表列中出现身份差距。
USE DatabaseName
GO
ALTER DATABASE SCOPED CONFIGURATION SET IDENTITY_CACHE = OFF
GO
- 将 -t272 注册到 SQL Server 启动参数(在 SQL Server 实例级别禁用 IDENTITY CACHE)
相关内容:
https://www.codeproject.com/Tips/668042/SQL-Server-2012-Auto-Identity-Column-Value-Jump-Is