介紹
從 SQL Server 2012 版本開始, 當SQL Server 實例重啟之後,表格的自動增長列的值會發生跳躍,而具體的跳躍值的大小是根據增長列的數據類型而定的。如果數據類型是 整型(int),那麼跳躍值為 1000;如果數據類型為 長整型(bigint),那麼跳躍值為 10000。從我們的項目來看,這種跳躍問題是不能被接受的,尤其是展示在客戶端的時候。這個奇怪的問題只在 SQL Server 2012 及更高的版本中存在,SQL Server 2012之前版本不存在此問題。
背景
幾天前,我們QA組的同事提出: 我們表格的自增列的值莫名奇妙的跳躍了 10000。也就是說,我們之前表格自增列的最後一個值為 2200,而現在新增一條記錄,自增列的值卻直接變成了 12200。在我們的業務邏輯中像這樣的情況是不允許展現在客戶端的,因此我們要解決此難題。
代碼使用
剛開始我們都很奇怪,這是怎麼發生的?我們通常不會手動向自增列插入任何值(向自增列手動插入值是可以的),自增列的值是由數據庫自行維護的。我們核心團隊的一位成員開始研究這個問題並找到了答案。現在,我想詳細講解下這個問題,以及我同事找到的解決方案。
如何重現此bug
你需要安裝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 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種解決方案將會影響此服務實例上的所有數據庫。
此文為譯文(英文水平有限,望諒解),原文鏈接:SQL Server 2012 Auto Identity Column Value Jump Issue