在 上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;
就我而言,结果是:
和运行
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_CURRENT
或sys.indentity_columns来查看它。无关但半有趣的事实:在创建表和开始执行插入之间有一个小窗口,其中查询中的源表不受架构稳定性锁的保护。如果并发进程碰巧更改了源表的架构(在创建目标之后,但在插入开始之前),则会引发错误 539: