SQL Server 重設Identity識別欄位的值(INT爆了)(轉載)

來源:互聯網
上載者:User

標籤:

一、背景

  SQL Server資料庫中表A中Id欄位的定義是:[Id] [int] IDENTITY(1,1),隨著資料的不斷增長,Id值已經接近2147483647(int的取值範圍為:-2 147 483 648 到 2 147 483 647)了,雖然已經對舊資料進行歸檔,但是這個表需要保留最近的1億資料,有什麼方法解決Id值就快爆的問題呢?

  解決上面的問題有兩個辦法:一個是修改表結構,把Id的int資料類型修改為bigint;第二個是重設Id(Identity識別欄位)的值,使它重新增長。

  當前標識值:current identity value,用於記錄和儲存最後一次系統分配的Id值;下次分配Id就是:當前標識值+識別值增量(通常為+1,也可以自行設定);

  當前列值:current column value,這Id值到目前為止的最大值;

 

二、重設過程

(一) 下面就測試重設Identity識別欄位,首先使用下面的SQL建立測試表:

--建立測試表CREATE TABLE [dbo].[Test_Identity](    [IdentityId] [int] IDENTITY(1,1) NOT NULL,    [Name] [nchar](10) NULL, CONSTRAINT [PK_testid] PRIMARY KEY CLUSTERED (    [IdentityId] ASC)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]) ON [PRIMARY]

(二) 顯示插入Id值,插入後表[Test_Identity]的記錄如Figure1所示,接著再隱式插入Id值,插入後表[Test_Identity]的記錄如Figure2所示。

--顯示插入Id值SET IDENTITY_INSERT [Test_Identity] ONINSERT INTO [Test_Identity](IdentityId,Name)SELECT 1000,‘name1‘SET IDENTITY_INSERT [Test_Identity] OFF--隱式插入Id值INSERT INTO [Test_Identity](Name)SELECT ‘name2‘

(Figure1:資料記錄)

(Figure2:資料記錄)

(三) DBCC CHECKIDENT(‘table_name‘, NORESEED)不重設當前標識值。DBCC CHECKIDENT 返回一個報表,它指明當前標識值和應有的標識值。執行下面的SQL語句,返回的資訊表示:當前標識值‘1001‘,當前列值‘1001‘,如 Figure2所示。

--查詢標識值DBCC CHECKIDENT(‘Test_Identity‘, NORESEED)/*檢查標識資訊: 當前標識值‘1001‘,當前列值‘1001‘。DBCC 執行完畢。如果DBCC 輸出了錯誤資訊,請與系統管理員聯絡。*/

(四) 再隱式插入Id值,插入後表[Test_Identity]的記錄如Figure3所示。所以執行上面的SQL語句是不會重設當前標識值的,可以放心執行。

--隱式插入Id值INSERT INTO [Test_Identity](Name)SELECT ‘name3‘

(Figure3:資料記錄)

--查詢標識值DBCC CHECKIDENT(‘Test_Identity‘, NORESEED)/*檢查標識資訊: 當前標識值‘1002‘,當前列值‘1002‘。DBCC 執行完畢。如果DBCC 輸出了錯誤資訊,請與系統管理員聯絡。*/

(五) DBCC CHECKIDENT (‘table_name‘) 或DBCC CHECKIDENT (‘table_name‘, RESEED) 如果表的當前標識值小於列中儲存的最大標識值,則使用識別欄位中的最大值對其進行重設。

因為上面返回結果是:當前標識值‘1002‘,當前列值‘1002‘,所以執行下面的SQL語句是沒有影響的,什麼時候才有影響呢?參考:(當在Figure4狀態下執行下面的SQL命令,結果就會如Figure7所示

--重設標識值DBCC CHECKIDENT(‘Test_Identity‘, RESEED)/*檢查標識資訊: 當前標識值‘1002‘,當前列值‘1002‘。DBCC 執行完畢。如果DBCC 輸出了錯誤資訊,請與系統管理員聯絡。*/

(六) DBCC CHECKIDENT(‘table_name‘, RESEED, new_reseed_value)當前值設定為 new_reseed_value。如果自建立表後沒有將行插入該表,則在執行 DBCC CHECKIDENT 後插入的第一行將使用 new_reseed_value 作為標識。否則,下一個插入的行將使用 new_reseed_value + 1。如果 new_reseed_value 的值小於識別欄位中的最大值,以後引用該表時將產生 2627 號錯誤資訊。

要理解上面的描述,可以進行下面的測試:

1) 重新設定當前值設定為new_reseed_value = 995,執行下面的SQL語句返回的資訊如下所示;

--重設標識值DBCC CHECKIDENT(‘Test_Identity‘, RESEED, 995)/*檢查標識資訊: 當前標識值‘1002‘,當前列值‘995‘。DBCC 執行完畢。如果DBCC 輸出了錯誤資訊,請與系統管理員聯絡。*/

2) 繼續往[Test_Identity]表插入資料,執行下面的SQL語句插入後的結果如Figure4所示;插入的Id值為new_reseed_value + 1 = 996;

--隱式插入Id值INSERT INTO [Test_Identity](Name)SELECT ‘name4‘

(Figure4:資料記錄)

3) 查看現在的標識值,與上面的進行對比,你就可以理解【當前標識值】與【當前列值】的意義了;

--查詢標識值DBCC CHECKIDENT(‘Test_Identity‘, NORESEED)/*檢查標識資訊: 當前標識值‘996‘,當前列值‘1002‘。DBCC 執行完畢。如果DBCC 輸出了錯誤資訊,請與系統管理員聯絡。*/

4) 繼續往[Test_Identity]表插入資料,執行3次後表的資料如Figure5所示;

--隱式插入Id值INSERT INTO [Test_Identity](Name)SELECT ‘name5‘

(Figure5:資料記錄)

5) 如果現在繼續往[Test_Identity]表插入資料會發生什麼事情呢?將產生 2627 號錯誤資訊,如下面的錯誤資訊;

訊息2627,層級14,狀態1,第2 行

違反了PRIMARY KEY 約束‘PK_testid‘。不能在對象‘dbo.Test_Identity‘ 中插入重複鍵。

語句已終止。

6) 下面來測試建立表後沒有插入行,如果這個時候執行重設標識值會發生什麼事情?清空[Test_Identity]表,再重新設定標識值,返回的資訊如下面所示;

--清空表truncate table [Test_Identity]--重設標識值DBCC CHECKIDENT(‘Test_Identity‘, RESEED, 995)/*檢查標識資訊: 當前標識值‘NULL‘,當前列值‘995‘。DBCC 執行完畢。如果DBCC 輸出了錯誤資訊,請與系統管理員聯絡。*/

7) 這個時候往[Test_Identity]表插入資料,資料就如Figure6所示,這說明了:“如果自建立表後沒有將行插入該表,則在執行 DBCC CHECKIDENT 後插入的第一行將使用 new_reseed_value 作為標識。

--隱式插入Id值INSERT INTO [Test_Identity](Name)SELECT ‘name5‘

(Figure6:資料記錄)

(Figure7:資料記錄)

8) 假如我們刪除了IdentityId為1000和1001的記錄,這個時候繼續插入資料,會重建1000和10001值嗎?效果如Figure10所示(重新覆蓋了);

--刪除和delete from [Test_Identity] where IdentityId=1000delete from [Test_Identity] where IdentityId=1001

(Figure8:資料記錄)

--重設標識值DBCC CHECKIDENT(‘Test_Identity‘, RESEED, 996)--隱式插入Id值INSERT INTO [Test_Identity](Name)SELECT ‘name6‘

(Figure9:資料記錄)

(Figure10:資料記錄)

(七) 總結:到這裡,我們已經可以解決Id值就快爆的問題了,因為我們舊的資料會定時歸檔,所以不會出現2627錯誤資訊;而另外一個情境是當出現 Figure5的時候,可以執行DBCC CHECKIDENT(‘Test_Identity‘, RESEED),設定為當前列最大值為標識值,防止出現2627錯誤資訊。

 

三、補充說明

在MySQL中,也有類似Identity的功能:

`IDs` int(11) unsigned NOT NULL AUTO_INCREMENT

在建立表的時候,會有一個選項AUTO_INCREMENT=17422061,直接可以設定起始值,還可以設定步長:

SHOW VARIABLES LIKE ‘auto_inc%‘;

起始值:auto_increment_offset

步長:auto_increment_increment

SET @auto_increment_increment=10;

SELECT LAST_INSERT_ID();

 

四、參考文獻

重設MSSQL的Identity識別欄位的值

DBCC CHECKIDENT (Transact-SQL)

SQLServer中的@@IDENTITY,SCOPE_IDENTITY和IDENT_CURRENT

SCOPE_IDENTITY (Transact-SQL)

 

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------

1、newid長度長,像4樓說的,每個頁面存放的數量就會少,查詢時要訪問的資料頁就多,通俗點說,就是I/O會更高。效能不見得好。
2、3樓說的newid無序,不適合做叢集索引,是正確的。
3、對於資料庫底層操作而言。由於數值型變成16進位時是明確的。而字元型或者其他類型到了底層會存在一些不可預知性。這樣需要額外的資訊來確定資料。所以一般建議使用數值型來做主鍵及索引,補充一下,最快的運算操作是2進位,其實也就是SQLServer的bit類型。但是由於索引需要考慮選擇性,所以不建議使用bit類型來做索引。選擇性不高。
4、newid號稱3000年內不會重複,但是幾乎沒有項目需要這麼舊。int類型足夠存放2億資料。對於大部分項目來說綽綽有餘。
5、你的文章僅僅突出不重複,而不是高效。
6、由於newid的不確定性,在匹配時,比如表關聯,會有一定的內耗。
綜上所述,不建議在非常特殊的情況下使用newid來做主鍵或者索引

SQL Server 重設Identity識別欄位的值(INT爆了)(轉載)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.