Depois de fazer esta pergunta comparando GUIDs seqüenciais e não sequenciais, tentei comparar o desempenho INSERT em 1) uma tabela com uma chave primária GUID inicializada sequencialmente com newsequentialid()
e 2) uma tabela com uma chave primária INT inicializada sequencialmente com identity(1,1)
. Eu esperaria que o último fosse mais rápido devido à menor largura de números inteiros, e também parece mais simples gerar um número inteiro seqüencial do que um GUID seqüencial. Mas, para minha surpresa, os INSERTs na tabela com a chave inteira eram significativamente mais lentos que a tabela GUID seqüencial.
Isso mostra o tempo médio de uso (ms) para a execução do teste:
NEWSEQUENTIALID() 1977
IDENTITY() 2223
Alguém pode explicar isso?
A seguinte experiência foi usada:
SET NOCOUNT ON
CREATE TABLE TestGuid2 (Id UNIQUEIDENTIFIER NOT NULL DEFAULT NEWSEQUENTIALID() PRIMARY KEY,
SomeDate DATETIME, batchNumber BIGINT, FILLER CHAR(100))
CREATE TABLE TestInt (Id Int NOT NULL identity(1,1) PRIMARY KEY,
SomeDate DATETIME, batchNumber BIGINT, FILLER CHAR(100))
DECLARE @BatchCounter INT = 1
DECLARE @Numrows INT = 100000
WHILE (@BatchCounter <= 20)
BEGIN
BEGIN TRAN
DECLARE @LocalCounter INT = 0
WHILE (@LocalCounter <= @NumRows)
BEGIN
INSERT TestGuid2 (SomeDate,batchNumber) VALUES (GETDATE(),@BatchCounter)
SET @LocalCounter +=1
END
SET @LocalCounter = 0
WHILE (@LocalCounter <= @NumRows)
BEGIN
INSERT TestInt (SomeDate,batchNumber) VALUES (GETDATE(),@BatchCounter)
SET @LocalCounter +=1
END
SET @BatchCounter +=1
COMMIT
END
DBCC showcontig ('TestGuid2') WITH tableresults
DBCC showcontig ('TestInt') WITH tableresults
SELECT batchNumber,DATEDIFF(ms,MIN(SomeDate),MAX(SomeDate)) AS [NEWSEQUENTIALID()]
FROM TestGuid2
GROUP BY batchNumber
SELECT batchNumber,DATEDIFF(ms,MIN(SomeDate),MAX(SomeDate)) AS [IDENTITY()]
FROM TestInt
GROUP BY batchNumber
DROP TABLE TestGuid2
DROP TABLE TestInt
ATUALIZAÇÃO: Modificando o script para executar as inserções com base em uma tabela TEMP, como nos exemplos de Phil Sandler, Mitch Wheat e Martin abaixo, também acho que a IDENTITY é mais rápida do que deveria ser. Mas essa não é a maneira convencional de inserir linhas, e ainda não entendo por que o experimento deu errado no início: mesmo que eu omita GETDATE () do meu exemplo original, IDENTITY () ainda é muito mais lento. Portanto, parece que a única maneira de fazer com que IDENTITY () supere NEWSEQUENTIALID () é preparar as linhas para inserir em uma tabela temporária e executar muitas inserções como inserção em lote usando esta tabela temporária. Em suma, acho que não encontramos uma explicação para o fenômeno, e o IDENTITY () ainda parece ser mais lento para a maioria dos usos práticos. Alguém pode explicar isso?
INT IDENTITY
IDENTITY
não requer um bloqueio de tabela. Conceitualmente, pude ver que você espera que ele esteja usando MAX (id) + 1, mas, na realidade, o próximo valor é armazenado. Na verdade, deve ser mais rápido do que encontrar o próximo GUID.