Después de hacer esta pregunta comparando GUID secuenciales y no secuenciales, traté de comparar el rendimiento de INSERT en 1) una tabla con una clave primaria GUID inicializada secuencialmente newsequentialid()
y 2) una tabla con una clave primaria INT inicializada secuencialmente identity(1,1)
. Esperaría que este último sea más rápido debido al menor ancho de los enteros, y también parece más simple generar un entero secuencial que un GUID secuencial. Pero para mi sorpresa, los INSERT en la tabla con la tecla entera fueron significativamente más lentos que la tabla secuencial GUID.
Esto muestra el uso de tiempo promedio (ms) para las ejecuciones de prueba:
NEWSEQUENTIALID() 1977
IDENTITY() 2223
¿Alguien puede explicar esto?
Se utilizó el siguiente experimento:
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
ACTUALIZACIÓN: Modificando el script para realizar las inserciones basadas en una tabla TEMP, como en los ejemplos de Phil Sandler, Mitch Wheat y Martin a continuación, también encuentro que IDENTITY es más rápido como debería ser. Pero esa no es la forma convencional de insertar filas, y todavía no entiendo por qué el experimento salió mal al principio: incluso si omito GETDATE () de mi ejemplo original, IDENTITY () sigue siendo mucho más lento. Por lo tanto, parece que la única forma de hacer que IDENTITY () supere a NEWSEQUENTIALID () es preparar las filas para insertar en una tabla temporal y realizar las muchas inserciones como inserción por lotes utilizando esta tabla temporal. En general, no creo que hayamos encontrado una explicación al fenómeno, e IDENTITY () todavía parece ser más lento para la mayoría de los usos prácticos. ¿Alguien puede explicar esto?
INT IDENTITY
IDENTITY
no requiere un bloqueo de mesa. Conceptualmente, pude ver que podría esperar que tome MAX (id) + 1, pero en realidad se almacena el siguiente valor. En realidad, debería ser más rápido que encontrar el siguiente GUID.