Nachdem ich diese Frage zum Vergleichen von sequentiellen und nicht-sequentiellen GUIDs gestellt hatte, versuchte ich, die INSERT-Leistung für 1) eine Tabelle mit einem GUID-Primärschlüssel, der sequentiell mit initialisiert wurde newsequentialid()
, und 2) eine Tabelle mit einem INT-Primärschlüssel, der sequentiell mit initialisiert wurde, zu vergleichen identity(1,1)
. Ich würde davon ausgehen, dass Letzteres aufgrund der geringeren Breite von Ganzzahlen am schnellsten ist, und es scheint auch einfacher zu sein, eine sequentielle Ganzzahl als eine sequentielle GUID zu generieren. Zu meiner Überraschung waren INSERTs in der Tabelle mit dem Integer-Schlüssel erheblich langsamer als in der sequentiellen GUID-Tabelle.
Dies zeigt die durchschnittliche Zeitnutzung (ms) für die Testläufe:
NEWSEQUENTIALID() 1977
IDENTITY() 2223
Kann mir jemand das erklären?
Das folgende Experiment wurde verwendet:
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: Wenn ich das Skript ändere, um die Einfügungen basierend auf einer TEMP-Tabelle durchzuführen, wie in den Beispielen von Phil Sandler, Mitch Wheat und Martin unten, finde ich auch, dass IDENTITY schneller ist, als es sein sollte. Dies ist jedoch nicht die herkömmliche Methode zum Einfügen von Zeilen, und ich verstehe immer noch nicht, warum das Experiment zunächst fehlgeschlagen ist: Auch wenn ich in meinem ursprünglichen Beispiel GETDATE () weglasse, ist IDENTITY () immer noch viel langsamer. Die einzige Möglichkeit, IDENTITY () besser als NEWSEQUENTIALID () zu machen, besteht darin, die Zeilen für das Einfügen in eine temporäre Tabelle vorzubereiten und die vielen Einfügungen als Batch-Insert mit dieser temporären Tabelle auszuführen. Alles in allem glaube ich nicht, dass wir eine Erklärung für das Phänomen gefunden haben, und IDENTITY () scheint für die meisten praktischen Anwendungen immer noch langsamer zu sein. Kann mir jemand das erklären?
INT IDENTITY
IDENTITY
ist keine Tabellensperre erforderlich. Konzeptionell konnte ich sehen, dass Sie vielleicht erwarten, dass es MAX (id) + 1 nimmt, aber in Wirklichkeit wird der nächste Wert gespeichert. Eigentlich sollte es schneller gehen, als die nächste GUID zu finden.