Em Microsoft SQL Server 2012 (SP1) - 11.0.3000.0 (X64)
, existe uma maneira de ver qual mecanismo o SQL Server usa para calcular os novos valores de identidade para tabelas criadas por SELECT INTO
?
DADOS DE AMOSTRA
-- 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;
No meu caso, os resultados são:
E correndo
DBCC CHECKIDENT('A')
retorna
Verificando informações de identidade: valor de identidade atual '1000', valor de coluna atual '1000'.
Criar nova tabela
Quando selecionamos um subconjunto em uma nova tabela, ele cria um novo valor de identidade atual:
SELECT * INTO #temp FROM dbo.A WHERE x1 = 0;
O valor mais alto na coluna de identidade desta nova tabela é 998 e quando verificamos sua próxima identidade:
DBCC CHECKIDENT('#temp')
Verificando informações de identidade: valor de identidade atual '998', valor de coluna atual '998'.
Como?
Como esses valores de identidade são inseridos na nova tabela com o valor mais alto definido corretamente como o valor de identidade atual da nova tabela?
SELECT INTO
tem duas fases (não visíveis nos planos de execução).Primeiro, ele cria uma tabela que corresponde aos metadados da consulta usada para criá-la. Isso acontece em uma transação do sistema, portanto, a tabela (vazia) criada continuará a existir mesmo que
SELECT INTO
seja agrupada em uma transação do usuário que é revertida. Ao final da primeira fase, temos uma tabela vazia que inclui uma coluna chamada A_ID com a propriedade identity.A segunda fase realiza uma inserção na tabela que a primeira fase criou. Essa inserção é feita com a semântica identity_insert , de modo que os valores de identidade da tabela de origem terminam no destino, inalterados. O valor mais alto realmente inserido é definido como o último valor usado. Você pode usar
IDENT_CURRENT
ou sys.indentity_columns para vê-lo.Fato não relacionado, mas semi-interessante: há uma pequena janela entre a criação da tabela e o início da inserção, onde a tabela de origem na consulta não é protegida por um bloqueio de estabilidade do esquema. Se um processo simultâneo alterar o esquema da tabela de origem (após a criação do destino, mas antes do início da inserção), o erro 539 será gerado: