Après avoir posé cette question en comparant les GUID séquentiels et non séquentiels, j'ai essayé de comparer les performances INSERT sur 1) une table avec une clé primaire GUID initialisée séquentiellement avec newsequentialid()
, et 2) une table avec une clé primaire INT initialisée séquentiellement avecidentity(1,1)
. Je m'attendrais à ce que ce dernier soit le plus rapide en raison de la largeur réduite des nombres entiers, et il semble également plus simple de générer un entier séquentiel qu'un GUID séquentiel. Mais à ma grande surprise, les INSERT de la table avec la clé entière étaient beaucoup plus lents que la table GUID séquentielle.
Cela montre le temps moyen d'utilisation (ms) pour les tests:
NEWSEQUENTIALID() 1977
IDENTITY() 2223
Quelqu'un peut-il expliquer cela?
L'expérience suivante a été utilisée:
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
UPDATE: Modification du script pour effectuer les insertions basées sur une table TEMP, comme dans les exemples de Phil Sandler, Mitch Wheat et Martin ci-dessous, je trouve également que IDENTITY est plus rapide que prévu. Mais ce n’est pas la méthode conventionnelle d’insertion de lignes et je ne comprends toujours pas pourquoi l’expérience a mal tourné au début: même si j’ignore GETDATE () de mon exemple initial, IDENTITY () est toujours beaucoup plus lent. Il semble donc que le seul moyen de rendre IDENTITY () supérieur à NEWSEQUENTIALID () est de préparer les lignes à insérer dans une table temporaire et d'effectuer les nombreuses insertions sous forme de batch-insert à l'aide de cette table temporaire. Au total, je ne pense pas que nous ayons trouvé d'explication au phénomène, et IDENTITY () semble toujours être plus lent pour la plupart des usages pratiques. Quelqu'un peut-il expliquer cela?
INT IDENTITY
IDENTITY
ne nécessite pas de verrou de table. Conceptuellement, je pouvais voir que vous pourriez vous attendre à ce qu'il prenne MAX (id) + 1, mais en réalité, la valeur suivante est stockée. En fait, cela devrait être plus rapide que de trouver le prochain GUID.