此文爲譯文(英文水平有限),原文連接: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種解決方案將會影響此服務實例上的全部數據庫。