Warum sind sequentielle GUID-Tasten in meinem Testfall schneller als sequentielle INT-Tasten?

39

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?

someName
quelle
4
Nur ein Gedanke: Könnte es sein, dass das Generieren einer neuen GUID durchgeführt werden kann, ohne die Tabelle einzubeziehen, während das Abrufen des nächsten verfügbaren Identitätswerts vorübergehend eine Art Sperre einführt, um sicherzustellen, dass zwei Threads / Verbindungen nicht denselben Wert erhalten? Ich rate nur wirklich. Interessante Frage!
Verärgerte Person
4
Wer sagt das? Es gibt viele Beweise, die sie nicht haben - sehen Sie, dass Kimberly Tripps Speicherplatz billig ist - das ist NICHT der Punkt! blog post - sie macht eine ziemlich umfangreiche Überprüfung, und GUIDs verlieren immer deutlich zuINT IDENTITY
marc_s
2
Nun, das obige Experiment zeigt das Gegenteil und die Ergebnisse sind wiederholbar.
someName
2
Für die Verwendung IDENTITYist 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.
4
Außerdem sollte die Füllspalte für die TestGuid2-Tabelle vermutlich CHAR (88) lauten, damit die Zeilen gleich groß werden
Mitch Wheat

Antworten:

19

Ich habe den Code von @Phil Sandler geändert, um den Effekt des Aufrufs von GETDATE () zu entfernen (möglicherweise sind Hardware-Effekte / Interrupts beteiligt?), Und die Zeilen auf dieselbe Länge gebracht.

[Seit SQL Server 2000 gab es mehrere Artikel zu Zeitproblemen und hochauflösenden Zeitgebern, daher wollte ich diesen Effekt minimieren.]

In einem einfachen Wiederherstellungsmodell mit Daten- und Protokolldatei, deren Größe sich nach den Anforderungen richtet, sind hier die Zeitangaben (in Sekunden): (Mit neuen Ergebnissen basierend auf dem unten angegebenen genauen Code aktualisiert.)

       Identity(s)  Guid(s)
       ---------    -----
       2.876        4.060    
       2.570        4.116    
       2.513        3.786   
       2.517        4.173    
       2.410        3.610    
       2.566        3.726
       2.376        3.740
       2.333        3.833
       2.416        3.700
       2.413        3.603
       2.910        4.126
       2.403        3.973
       2.423        3.653
    -----------------------
Avg    2.650        3.857
StdDev 0.227        0.204

Der verwendete Code:

SET NOCOUNT ON

CREATE TABLE TestGuid2 (Id UNIQUEIDENTIFIER NOT NULL DEFAULT NEWSEQUENTIALID() PRIMARY KEY,
SomeDate DATETIME, batchNumber BIGINT, FILLER CHAR(88))

CREATE TABLE TestInt (Id Int NOT NULL identity(1,1) PRIMARY KEY,
SomeDate DATETIME, batchNumber BIGINT, FILLER CHAR(100))

DECLARE @Numrows INT = 1000000

CREATE TABLE #temp (Id int NOT NULL Identity(1,1) PRIMARY KEY, rowNum int, adate datetime)

DECLARE @LocalCounter INT = 0

--put rows into temp table
WHILE (@LocalCounter < @NumRows)
BEGIN
    INSERT INTO #temp(rowNum, adate) VALUES (@LocalCounter, GETDATE())
    SET @LocalCounter += 1
END

--Do inserts using GUIDs
DECLARE @GUIDTimeStart DateTime = GETDATE()
INSERT INTO TestGuid2 (SomeDate, batchNumber) 
SELECT adate, rowNum FROM #temp
DECLARE @GUIDTimeEnd  DateTime = GETDATE()

--Do inserts using IDENTITY
DECLARE @IdTimeStart DateTime = GETDATE()
INSERT INTO TestInt (SomeDate, batchNumber) 
SELECT adate, rowNum FROM #temp
DECLARE @IdTimeEnd DateTime = GETDATE()

SELECT DATEDIFF(ms, @IdTimeStart, @IdTimeEnd) AS IdTime, DATEDIFF(ms, @GUIDTimeStart, @GUIDTimeEnd) AS GuidTime

DROP TABLE TestGuid2
DROP TABLE TestInt
DROP TABLE #temp
GO

Nachdem ich die Untersuchung von @ Martin gelesen hatte, lief ich in beiden Fällen erneut mit dem vorgeschlagenen TOP (@num), d. H

...
--Do inserts using GUIDs
DECLARE @num INT = 2147483647; 
DECLARE @GUIDTimeStart DATETIME = GETDATE(); 
INSERT INTO TestGuid2 (SomeDate, batchNumber) 
SELECT TOP(@num) adate, rowNum FROM #temp; 
DECLARE @GUIDTimeEnd DATETIME = GETDATE();

--Do inserts using IDENTITY
DECLARE @IdTimeStart DateTime = GETDATE()
INSERT INTO TestInt (SomeDate, batchNumber) 
SELECT TOP(@num) adate, rowNum FROM #temp;
DECLARE @IdTimeEnd DateTime = GETDATE()
...

und hier sind die Timing-Ergebnisse:

       Identity(s)  Guid(s)
       ---------    -----
       2.436        2.656
       2.940        2.716
       2.506        2.633
       2.380        2.643
       2.476        2.656
       2.846        2.670
       2.940        2.913
       2.453        2.653
       2.446        2.616
       2.986        2.683
       2.406        2.640
       2.460        2.650
       2.416        2.720

    -----------------------
Avg    2.426        2.688
StdDev 0.010        0.032

Ich konnte den tatsächlichen Ausführungsplan nicht abrufen, da die Abfrage nie zurückgegeben wurde! Es scheint, dass ein Fehler wahrscheinlich ist. (Ausführen von Microsoft SQL Server 2008 R2 (RTM) - 10.50.1600.1 (X64))

Mitch Weizen
quelle
7
Verdeutlicht anschaulich das entscheidende Element eines guten Benchmarks: Stellen Sie sicher, dass Sie immer nur eine Sache gleichzeitig messen.
Aaronaught
Welchen Plan bekommen Sie hier? Hat es einen SORTOperator für die GUIDs?
Martin Smith
@Martin: Hi, ich habe die Pläne nicht überprüft (ein paar Dinge auf einmal erledigen :)). Ich schaue später nach ...
Mitch Wheat
@Mitch - Feedback dazu? Ich vermute eher, dass Sie hier vor allem die Zeit messen, die zum Sortieren der Guids für große Inserts benötigt wird, was zwar interessant ist, aber nicht die ursprüngliche Frage des OP beantwortet Zeileneinfügungen beim Testen des OP.
Martin Smith
2
@Mitch - Obwohl ich je mehr darüber nachdenke, desto weniger verstehe ich, warum irgendjemand NEWSEQUENTIALIDsowieso jemals verwenden möchte . Es wird den Index vertiefen, 20% mehr Datenseiten im OP-Fall verwenden und wird nur garantiert immer größer, bis die Maschine neu gestartet wird identity. Es scheint in diesem Fall nur, dass der Abfrageplan einen weiteren unnötigen hinzufügt!
Martin Smith
19

Bei einer neuen Datenbank in einem einfachen Wiederherstellungsmodell mit einer Datendatei mit einer Größe von 1 GB und einer Protokolldatei mit einer Größe von 3 GB (Laptop-Computer, beide Dateien auf demselben Laufwerk) und einem Wiederherstellungsintervall von 100 Minuten (um zu vermeiden, dass ein Prüfpunkt die Ergebnisse verzerrt) sehe ich ähnliche Ergebnisse zu Ihnen mit der einzelnen Reihe inserts.

Ich habe drei Fälle getestet: In jedem Fall habe ich 20 Stapel mit jeweils 100.000 Zeilen in die folgenden Tabellen eingefügt. Die vollständigen Skripte finden Sie im Revisionsverlauf dieser Antwort .

CREATE TABLE TestGuid
  (
     Id          UNIQUEIDENTIFIER NOT NULL DEFAULT NEWSEQUENTIALID() PRIMARY KEY,
     SomeDate    DATETIME, batchNumber BIGINT, FILLER CHAR(100)
  )

CREATE TABLE TestId
  (
     Id          Int NOT NULL identity(1, 1) PRIMARY KEY,
     SomeDate    DATETIME, batchNumber BIGINT, FILLER CHAR(100)
  )

CREATE TABLE TestInt
  (
     Id          Int NOT NULL PRIMARY KEY,
     SomeDate    DATETIME, batchNumber BIGINT, FILLER  CHAR(100)
  )  

Für die dritte Tabelle fügte der Test Zeilen mit einem inkrementierenden IdWert ein, der jedoch selbst berechnet wurde, indem der Wert einer Variablen in einer Schleife inkrementiert wurde.

Die Mittelung der über die 20 Chargen genommenen Zeit ergab die folgenden Ergebnisse.

NEWSEQUENTIALID() IDENTITY()  INT
----------------- ----------- -----------
1999              2633        1878

Fazit

Es scheint also definitiv ein Overhead des identityErstellungsprozesses zu sein, der für die Ergebnisse verantwortlich ist. Für die selbst berechnete inkrementierende Ganzzahl stimmen die Ergebnisse viel besser mit den erwarteten Ergebnissen überein, wenn nur die E / A-Kosten berücksichtigt werden.

Wenn ich den oben beschriebenen Einfügungscode in gespeicherte Prozeduren einfüge und überprüfe sys.dm_exec_procedure_stats, werden die folgenden Ergebnisse angezeigt

proc_name      execution_count      total_worker_time    last_worker_time     min_worker_time      max_worker_time      total_elapsed_time   last_elapsed_time    min_elapsed_time     max_elapsed_time     total_physical_reads last_physical_reads  min_physical_reads   max_physical_reads   total_logical_writes last_logical_writes  min_logical_writes   max_logical_writes   total_logical_reads  last_logical_reads   min_logical_reads    max_logical_reads
-------------- -------------------- -------------------- -------------------- -------------------- -------------------- -------------------- -------------------- -------------------- -------------------- -------------------- -------------------- -------------------- -------------------- -------------------- -------------------- -------------------- -------------------- -------------------- -------------------- -------------------- --------------------
IdentityInsert 20                   45060360             2231067              2094063              2645079              45119362             2234067              2094063              2660080              0                    0                    0                    0                    32505                1626                 1621                 1626                 6268917              315377               276833               315381
GuidInsert     20                   34829052             1742052              1696051              1833055              34900053             1744052              1698051              1838055              0                    0                    0                    0                    35408                1771                 1768                 1772                 6316837              316766               298386               316774

In diesen Ergebnissen total_worker_timeliegt es also um 30% höher. Dies stellt dar

Gesamtmenge der CPU-Zeit in Mikrosekunden, die von den Ausführungen dieser gespeicherten Prozedur seit ihrer Kompilierung verbraucht wurde.

Es sieht also einfach so aus, als ob der Code, der den IDENTITYWert generiert, mehr CPU- NEWSEQUENTIALID()Kapazität hat als der Code, der den Wert generiert ausreichend hoch, um die zusätzlichen logischen Lese- und Schreibvorgänge aufzuwiegen, die aufgrund der größeren Schlüsselbreite anfallen. (Anmerkung: Itzik Ben Gan hat hier ähnliche Tests durchgeführt und eine 2µs Strafe pro Insert festgestellt.)

Warum ist IDENTITYdie CPU also intensiver als UuidCreateSequential?

Ich glaube, das wird in diesem Artikel erklärt . Für jeden zehnten identitygenerierten Wert muss SQL Server die Änderung in die Systemtabellen auf der Festplatte schreiben

Was ist mit MultiRow Inserts?

Wenn die 100.000 Zeilen in eine einzelne Anweisung eingefügt werden, verschwindet der Unterschied mit vielleicht noch geringem Vorteil für den GUIDFall, aber bei weitem nicht so eindeutigen Ergebnissen. Der Durchschnitt für 20 Chargen in meinem Test war

NEWSEQUENTIALID() IDENTITY()
----------------- -----------
1016              1088

Der Grund dafür, dass es nicht den Nachteil gibt, der in Phils Code und Mitchs erstem Satz von Ergebnissen zu sehen ist, ist, dass der Code, den ich für die mehrzeilige Einfügung verwendet habe, zufällig verwendet wurde SELECT TOP (@NumRows). Dadurch konnte das Optimierungsprogramm die Anzahl der einzufügenden Zeilen nicht richtig schätzen.

Dies scheint von Vorteil zu sein, da es einen bestimmten Wendepunkt gibt, an dem eine zusätzliche Sortieroperation für die (angeblich sequentiellen!) GUIDS hinzugefügt wird .

GUID-Sortierung

Diese Sortieroperation ist aus dem erläuternden Text in BOL nicht erforderlich .

Erstellt eine GUID, die größer ist als jede GUID, die zuvor von dieser Funktion auf einem angegebenen Computer seit dem Start von Windows generiert wurde. Nach dem Neustart von Windows kann die GUID in einem niedrigeren Bereich erneut gestartet werden, ist jedoch weiterhin global eindeutig.

Daher schien es mir ein Fehler oder eine fehlende Optimierung zu sein, dass SQL Server nicht erkennt, dass die Ausgabe des Computing-Skalars bereits vorsortiert ist, wie dies anscheinend bereits für die identitySpalte der Fall ist . ( Bearbeiten Ich habe dies gemeldet und das unnötige Sortierproblem ist jetzt in Denali behoben. )

Martin Smith
quelle
Nicht, dass es eine Menge Auswirkungen hat, aber nur im Interesse der Klarheit ist die von Denny angegebene Zahl, 20 zwischengespeicherte Identitätswerte, falsch - sie sollte 10 sein.
Aaron Bertrand
@ AaronBertrand - Danke. Der Artikel, den Sie verlinkt haben, ist am informativsten.
Martin Smith
8

Ganz einfach: Mit GUID ist es billiger, die nächste Nummer in der Zeile zu generieren als mit IDENTITY (Der aktuelle Wert der GUID muss nicht gespeichert werden, die IDENTITY muss sein). Dies gilt auch für NEWSEQUENTIALGUID.

Sie könnten den Test fairer gestalten und einen SEQUENCER mit einem großen CACHE verwenden - das ist billiger als IDENTITY.

Aber wie MR sagt, haben GUIDs einige wesentliche Vorteile. Tatsächlich sind sie VIEL skalierbarer als IDENTITY-Spalten (aber nur, wenn sie NICHT sequenziell sind).

Siehe: http://blog.kejser.org/2011/10/05/boosting-insert-speed-by-generating-scalable-keys/

Thomas Kejser
quelle
Ich denke, Sie haben vermisst, dass sie sequentielle Guids verwenden.
Martin Smith
Martin: Das Argument gilt auch für die sequentielle GUID. IDENTITY muss gespeichert werden (um nach einem Neustart auf den alten Wert zurückzukehren). Die sequenzielle GUID hat diese Einschränkung nicht.
Thomas Kejser
2
Ja, nach meinem Kommentar ist Ihnen klar geworden, dass Sie über das dauerhafte Speichern und nicht über das Speichern im Speicher sprechen. Für 2012 wird allerdings auch ein Cache verwendet IDENTITY. daher hier Beschwerden
Martin Smith
4

Diese Art von Frage fasziniert mich. Warum musstest du es an einem Freitagabend posten? :)

Ich denke, auch wenn Ihr Test NUR zur Messung der INSERT-Leistung gedacht ist, haben Sie (möglicherweise) eine Reihe von Faktoren eingeführt, die irreführend sein könnten (Schleifen, eine lang andauernde Transaktion usw.).

Ich bin nicht ganz davon überzeugt, dass meine Version irgendetwas beweist, aber Identität funktioniert besser als die darin enthaltenen GUIDs (3,2 Sekunden gegenüber 6,8 Sekunden auf einem Heim-PC):

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 @Numrows INT = 1000000

CREATE TABLE #temp (Id int NOT NULL Identity(1,1) PRIMARY KEY, rowNum int)

DECLARE @LocalCounter INT = 0

--put rows into temp table
WHILE (@LocalCounter < @NumRows)
BEGIN
    INSERT INTO #temp(rowNum) VALUES (@LocalCounter)
    SET @LocalCounter += 1
END

--Do inserts using GUIDs
DECLARE @GUIDTimeStart DateTime = GETDATE()
INSERT INTO TestGuid2 (SomeDate, batchNumber) 
SELECT GETDATE(), rowNum FROM #temp
DECLARE @GUIDTimeEnd  DateTime = GETDATE()

--Do inserts using IDENTITY
DECLARE @IdTimeStart DateTime = GETDATE()
INSERT INTO TestInt (SomeDate, batchNumber) 
SELECT GETDATE(), rowNum FROM #temp
DECLARE @IdTimeEnd DateTime = GETDATE()

SELECT DATEDIFF(ms, @IdTimeStart, @IdTimeEnd) AS IdTime
SELECT DATEDIFF(ms, @GUIDTimeStart, @GUIDTimeEnd) AS GuidTime

DROP TABLE TestGuid2
DROP TABLE TestInt
DROP TABLE #temp
Phil Sandler
quelle
Der andere Faktor, den niemand erwähnt hat, ist das Datenbankwiederherstellungsmodell und das Wachstum von Protokolldateien ...
Mitch Wheat
@Mitch auf eine neue Datenbank in einfachen Wiederherstellungsmodell mit Daten und Protokolldatei in beiden Größen über das, was erforderlich ist, bekomme ich ähnliche Ergebnisse wie das OP.
Martin Smith
Ich habe gerade einen Zeitplan von 2,560 Sekunden für Identity und 3,666 Sekunden für Guid (in einem einfachen Wiederherstellungsmodell mit Daten- und Protokolldateien, deren Größe über der erforderlichen Größe liegt)
Mitch Wheat,
@Mitch - Auf dem OP-Code mit allem in der gleichen Transaktion oder auf Phils Code?
Martin Smith
Deshalb kommentiere ich diesen Poster-Code hier. Ich habe auch den Code gepostet, den ich verwendet habe ...
Mitch Wheat
3

Ich habe Ihr Beispielskript mehrmals ausgeführt und einige Änderungen an der Anzahl und Größe der Stapel vorgenommen (und vielen Dank, dass Sie es bereitgestellt haben).

Zuerst möchte ich sagen, dass Sie nur einen Aspekt der Leistung der Tasten messen - die INSERTGeschwindigkeit. Wenn Sie sich also nicht speziell darum kümmern, Daten so schnell wie möglich in die Tabellen zu bekommen, steckt viel mehr in diesem Tier.

Meine Ergebnisse waren im Allgemeinen ähnlich wie bei Ihnen. Allerdings würde ich diese Varianz erwähnt INSERTGeschwindigkeit zwischen GUIDund IDENTITY(int) ist etwas größer mit GUIDals mit IDENTITY- vielleicht +/- 10% zwischen den Läufen. Die verwendeten Chargen IDENTITYvariierten jeweils um weniger als 2 - 3%.

Zu beachten ist auch, dass meine Testbox deutlich weniger leistungsstark ist als Ihre, sodass ich kleinere Zeilenzahlen verwenden musste.

Yuck
quelle
Wenn die PK eine GUID ist, verwendet die Engine möglicherweise keinen Index, sondern einen Hashing-Algorithmus, um den physischen Speicherort des entsprechenden Datensatzes zu ermitteln? Einfügungen in eine Sparse-Tabelle mit gehashten Primärschlüsseln sind aufgrund des fehlenden Index-Overheads immer schneller als Einfügungen in eine Tabelle mit einem Index für den Primärschlüssel. Es ist nur eine Frage - stimmen Sie mich nicht ab, wenn die Antwort Nein lautet. Geben Sie einfach den Link zur Behörde an.
1

Ich werde für dasselbe Thema auf eine andere Conv zum Stackoverflow zurückgreifen - https://stackoverflow.com/questions/170346/was-ist-die-Leistungsverbesserung-der-Sequenz-Guid-über-Standard-Guid

Ich weiß, dass bei sequenziellen GUIDs die Indexnutzung aufgrund der geringen Blattbewegung besser ist und daher die HD-Suche verringert wird. Ich würde daher denken, dass die Einfügungen auch schneller sind, da sie die Schlüssel nicht über eine große Anzahl von Seiten verteilen müssen.

Nach meiner persönlichen Erfahrung ist es bei der Implementierung einer großen Datenbank mit hohem Datenverkehr besser, GUIDs zu verwenden, da diese für die Integration in andere Systeme viel skalierbarer sind. Das gilt insbesondere für die Replikation und die int / bigint-Grenzen. Nicht, dass Ihnen die bigints ausgehen würden, aber irgendwann werden Sie und fahren zurück.

HERR
quelle
1
BIGINTs gehen Ihnen nicht aus, niemals ... Siehe hierzu: sqlmag.com/blog/it-possible-run-out-bigint-values
Thomas Kejser