Sql-Server

有沒有辦法查看 SQL Server 2012 如何定義新身份?

  • May 13, 2016

關於Microsoft SQL Server 2012 (SP1) - 11.0.3000.0 (X64),有沒有辦法查看 SQL Server 使用什麼機制來計算由創建的表的新標識值SELECT INTO


樣本數據

-- Create our base table
CREATE TABLE dbo.A
(A_ID INT IDENTITY(1, 1),
x1 INT,
noise1 int DEFAULT 1,
noise2 char(1) DEFAULT 'S',
noise3 date DEFAULT GETUTCDATE(),
noise4 bit DEFAULT 0);

-- Create random data between the range of [0-3]
INSERT INTO dbo.A(x1)
SELECT s1000.n FROM
( SELECT TOP (10) n = 1 FROM sys.columns) AS s10 -- 10
CROSS JOIN
( SELECT TOP (10) n = 1 FROM sys.columns) AS s100 -- 10 * 10
CROSS JOIN
( SELECT TOP (10) n = ABS(CHECKSUM(NEWID())) % 4 FROM sys.columns) AS s1000; -- 100 * 10

SELECT * FROM dbo.A ORDER BY A_ID DESC;

就我而言,結果是:

dbo.A 結果

並執行

DBCC CHECKIDENT('A')

返回

檢查身份資訊:目前身份值'1000’,目前列值'1000’。


創建新表

當我們將一個子集選擇到一個新表中時,它會創建一個新的目前標識值:

SELECT * INTO #temp FROM dbo.A WHERE x1 = 0;

這個新表的標識列中的最大值是 998,當我們檢查它的下一個標識時:

DBCC CHECKIDENT('#temp')

檢查身份資訊:目前身份值'998’,目前列值'998’。


如何?

如何將這些標識值插入到新表中,並將最高值正確設置為新表的目前標識值?

SELECT INTO有兩個階段(在執行計劃中不可見)。

首先,它創建一個與用於創建它的查詢的元數據相匹配的表。這發生在系統事務中,因此(空)創建的表將繼續存在,即使它SELECT INTO被包裝在回滾的使用者事務中。在第一階段結束時,我們有一個空表,其中包含一個名為A_ID的列和標識屬性。

第二階段在第一階段創建的表中執行插入操作。此插入是使用identity_insert語義完成的,因此源表中的標識值最終在目標中,不變。實際插入的最大值被設置為最後使用的值。您可以使用IDENT_CURRENTsys.indentity_columns查看它。

不相關但半有趣的事實:在創建表和開始執行插入之間有一個小視窗,其中查詢中的源表不受模式穩定性鎖的保護。如果並發程序碰巧更改了源表的架構(在創建目標之後,但在插入開始之前),則會引發錯誤 539:

創建目標表後,架構發生了變化。重新執行 Select Into 查詢。

引用自:https://dba.stackexchange.com/questions/138338