此文为译文(英文水平有限),原文连接:SQL Server 2012 Auto Identity Column Value Jump Issue数据库
介绍缓存
从 SQL Server 2012 版本开始, 当SQL Server 实例重启以后,表格的自动增加列的值会发生跳跃,而具体的跳跃值的大小是根据增加列的数据类型而定的。若是数据类型是 整型(int),那么跳跃值为 1000;若是数据类型为 长整型(bigint),那么跳跃值为 10000。从咱们的项目来看,这种跳跃问题是不能被接受的,尤为是展现在客户端的时候。这个奇怪的问题只在 SQL Server 2012 及更高的版本中存在,SQL Server 2012以前版本不存在此问题。服务器
背景测试
几天前,咱们QA组的同事提出: 咱们表格的自增列的值莫名奇妙的跳跃了 10000。也就是说,咱们以前表格自增列的最后一个值为 2200,而如今新增一条记录,自增列的值却直接变成了 12200。在咱们的业务逻辑中像这样的状况是不容许展示在客户端的,所以咱们要解决此难题。spa
代码使用code
刚开始咱们都很奇怪,这是怎么发生的?咱们一般不会手动向自增列插入任何值(向自增列手动插入值是能够的),自增列的值是由数据库自行维护的。咱们核心团队的一位成员开始研究这个问题并找到了答案。如今,我想详细讲解下这个问题,以及我同事找到的解决方案。blog
如何重现此bugip
你须要安装SQL Server 2012 而后建立一个测试数据库。以后再建立一个带有自增列的表格:作用域
create table MyTestTable(Id int Identity(1,1), Name varchar(255));
如今插入两条数据:get
insert into MyTestTable(Name) values ('Mr.Tom'); insert into MyTestTable(Name) values ('Mr.Jackson');
查看结果:
SELECT Id, Name FROM MyTestTable;
此时结果和咱们预期的同样。 如今重启你的 SQL Server Service。重启SQL服务有多种方法,咱们这里经过 SQL Server 管理器来重启:
重启以后,咱们向刚才的表格再插入2条数据:
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吗?
微软声明这是一个功能而并不是bug, 在不少场景下是颇有用处的。 可是在咱们的案例中,咱们并不须要这样的一个功能,由于这个自增数据是要展现给客户的,客户若是看到这样跳跃性的数据,他们会感到很奇怪。而且跳跃值是根据你重启SQL Server的次数决定的。若是此数据不向客户展现,或许还能够接受。所以此功能一般只适合在内部使用。
解决方案
若是咱们对微软提供的这个 “功能” 不感兴趣,咱们能够经过两种途径来关闭它。
1. 使用序列 (Sequence)
2. 为SQL Server 注册启动参数 -t272
使用序列
首先,咱们须要移除表格的自增列。而后建立一个不带缓存功能的序列,根据此序列插入数值。 下面是示例代码:
CREATE SEQUENCE Id_Sequence AS INT START WITH 1 INCREMENT BY 1 MINVALUE 0 NO MAXVALUE NO CACHE insert into MyTestTable values(NEXT VALUE FOR Id_Sequence, 'Mr.Tom'); insert into MyTestTable values(NEXT VALUE FOR Id_Sequence, 'Mr.Jackson');
注册启动参数 -t272
打开SQL Server配置管理器。 选择 SQL Server 2012 实例,右键, 选择属性菜单。在弹出的窗口中找到启动参数,而后注册 -t272。 完成以后重启下图中的SQL Server(SQLSERVER2012), 以后进行bug重现的操做,验证问题是否已解决。
额外说明
若是在你的数据库中有不少自增列的表,而且这些表都存在数值跳跃问题,那么采用第2种方案更好一些。由于它很是简单,而且做用域是服务器级别的。采用第2种解决方案将会影响此服务实例上的全部数据库。