111 Stimmen

UUID-Leistung in MySQL?

Wir erwägen die Verwendung von UUID-Werten als Primärschlüssel für unsere MySQL-Datenbank. Die Daten, die eingefügt werden, werden von Dutzenden, Hunderten oder sogar Tausenden von entfernten Computern generiert und mit einer Rate von 100-40.000 Einfügungen pro Sekunde eingefügt, und wir werden nie irgendwelche Aktualisierungen vornehmen.

Die Datenbank selbst wird in der Regel etwa 50 Mio. Datensätze umfassen, bevor wir beginnen, die Daten zu bereinigen, also keine riesige Datenbank, aber auch keine winzige. Wir planen auch auf InnoDB zu laufen, obwohl wir offen sind, das zu ändern, wenn es eine bessere Engine für das, was wir tun, gibt.

Wir waren bereit, mit Java's Type 4 UUID zu arbeiten, aber beim Testen haben wir ein seltsames Verhalten festgestellt. Zum einen speichern wir als varchar(36) und ich erkenne jetzt, dass wir mit binary(16) besser dran wären - aber wie viel besser dran ist, weiß ich nicht.

Die wichtigere Frage ist: Wie stark beeinträchtigen diese Zufallsdaten den Index, wenn wir 50 Millionen Datensätze haben? Wären wir besser dran, wenn wir zum Beispiel eine UUID vom Typ 1 verwenden würden, bei der die äußersten linken Bits mit einem Zeitstempel versehen sind? Oder sollten wir die UUIDs vielleicht ganz weglassen und automatische Primärschlüssel in Betracht ziehen?

Ich bin auf der Suche nach allgemeinen Gedanken/Tipps zur Leistung verschiedener Arten von UUIDs, wenn sie als Index/Primärschlüssel in MySQL gespeichert werden. Vielen Dank!

95voto

Kat Lim Ruiz Punkte 2201

Bei meiner Arbeit verwenden wir UUID als PKs. Was ich Ihnen aus Erfahrung sagen kann, ist, dass Sie diese nicht als PKs verwenden sollten (übrigens auch nicht für SQL Server).

Wenn man weniger als 1000 Datensätze hat, ist das in Ordnung, aber wenn man Millionen hat, ist es das Schlimmste, was man tun kann. Und warum? Weil UUIDs nicht sequentiell sind, so dass MSSQL jedes Mal, wenn ein neuer Datensatz eingefügt wird, die richtige Seite suchen muss, in die der Datensatz eingefügt werden soll, und dann den Datensatz einfügt. Die wirklich hässliche Folge davon ist, dass die Seiten am Ende alle unterschiedlich groß und fragmentiert sind, so dass wir jetzt regelmäßig die Fragmentierung aufheben müssen.

Wenn Sie ein Autoinkrement verwenden, geht MSSQL immer zur letzten Seite, und Sie enden mit gleich großen Seiten (in der Theorie), so dass die Leistung zur Auswahl dieser Datensätze viel besser ist (auch weil die INSERTs nicht die Tabelle/Seite für so lange blockieren).

Der große Vorteil der Verwendung von UUIDs als PKs besteht jedoch darin, dass es bei der Zusammenführung von DB-Clustern keine Konflikte geben wird.

Ich würde das folgende Modell empfehlen: 1. PK INT Identität 2. Zusätzliche Spalte, die automatisch als UUID generiert wird.

Auf diese Weise ist der Zusammenführungsprozess möglich (die UUID wäre Ihr ECHTER Schlüssel, während die PK nur etwas Vorläufiges wäre, das Ihnen eine gute Leistung bietet).

HINWEIS: Die beste Lösung ist die Verwendung von NEWSEQUENTIALID (wie ich in den Kommentaren sagte), aber für Legacy-Anwendungen mit wenig Zeit zum Refactoring (und noch schlimmer, ohne Kontrolle aller Einfügungen) ist dies nicht möglich. Aber in der Tat ab 2017, würde ich sagen, die beste Lösung hier ist NEWSEQUENTIALID oder tun Guid.Comb mit NHibernate.

Ich hoffe, das hilft

40voto

Dancrumb Punkte 24965

Eine UUID ist eine universell eindeutige ID. Es ist der universelle Teil, den Sie hier in Betracht ziehen sollten.

Haben Sie wirklich müssen die IDs universell eindeutig sein? Wenn ja, dann sind UUIDs möglicherweise Ihre einzige Wahl.

Ich würde Ihnen dringend empfehlen, wenn Sie hacer UUIDs verwenden, speichern Sie sie als Zahl und nicht als Zeichenfolge. Wenn Sie mehr als 50 Mio. Datensätze haben, wird die Einsparung an Speicherplatz Ihre Leistung verbessern (obwohl ich nicht sagen kann, um wie viel).

Wenn Ihre IDs nicht universell eindeutig sein müssen, dann glaube ich nicht, dass Sie viel besser tun können, als nur mit auto_increment, die garantiert, dass IDs innerhalb einer Tabelle eindeutig sein werden (da der Wert jedes Mal erhöht wird)

28voto

Kyle Rosendo Punkte 24351

Dabei ist zu berücksichtigen, dass Autoincrements einzeln generiert werden und nicht mit einer parallelen Lösung gelöst werden können. Der Kampf für die Verwendung von UUIDs läuft letztendlich darauf hinaus, was Sie erreichen wollen und was Sie möglicherweise opfern.

Zur Leistung, kurz :

Eine UUID wie die obige ist 36 Zeichen lang, einschließlich Bindestrichen. Wenn Sie diese VARCHAR(36) speichern, werden Sie wird die Vergleichsleistung drastisch. Dies ist Ihr Primär Schlüssel, Sie wollen nicht, dass er langsam ist.

Auf Bit-Ebene besteht eine UUID aus 128 Bit, was bedeutet, dass sie in 16 Bytes passt, dies ist nicht sehr gut lesbar, aber es hält den Speicherplatz gering und ist nur 4-mal größer als ein 32-Bit-Int, oder 2-mal größer als ein 64-Bit-Int. Ich werde eine VARBINARY(16) verwenden. Theoretisch kann dies ohne großen viel Overhead.

Ich empfehle die Lektüre der beiden folgenden Beiträge:

Ich denke, dass die beiden Ihre Frage beantworten.

4voto

Glenn J. Schworak Punkte 291

Ich neige dazu, UUID zu vermeiden, einfach weil es ein Schmerz zu speichern und ein Schmerz als Primärschlüssel zu verwenden, aber es gibt Vorteile. Der wichtigste ist, dass sie einmalig sind.

Normalerweise löse ich das Problem und vermeide UUID, indem ich doppelte Schlüsselfelder verwende.

KOLLEKTOR = EINDEUTIG EINER MASCHINE ZUGEWIESEN

ID = RECORD COLLECTED BY THE COLLECTOR (Feld auto_inc)

Dies bietet mir zwei Möglichkeiten. Schnelligkeit bei der automatischen Erfassung von Feldern und Einzigartigkeit der Daten, die an einem zentralen Ort gespeichert werden, nachdem sie gesammelt und gruppiert wurden. Außerdem weiß ich beim Durchsuchen der Daten, wo sie erfasst wurden, was für meine Bedürfnisse oft sehr wichtig ist.

Ich habe bei der Arbeit mit anderen Datensätzen für Kunden viele Fälle gesehen, in denen sie sich für die Verwendung von UUID entschieden haben, dann aber immer noch ein Feld für den Ort haben, an dem die Daten gesammelt wurden, was wirklich eine Verschwendung von Arbeit ist. Die Verwendung von zwei (oder bei Bedarf auch mehr) Feldern als Schlüssel ist wirklich hilfreich.

Ich habe einfach zu viele Leistungseinbußen bei der Verwendung von UUID gesehen. Sie fühlen sich wie ein Betrug an...

3voto

Bouke Versteegh Punkte 3240

Wie wäre es, wenn Sie statt der zentralen Generierung eindeutiger Schlüssel für jede Einfügung einzelnen Servern Blöcke von Schlüsseln zuweisen würden? Wenn sie keine Schlüssel mehr haben, können sie einen neuen Block anfordern. Dann lösen Sie das Problem des Overheads, indem Sie für jede Einfügung eine Verbindung herstellen.

Der Keyserver behält die nächste verfügbare ID

  • Server 1 fordert id-Block an.
  • Keyserver gibt zurück (1,1000)
    Server 1 kann 1000 Datensätze einfügen, bis er einen neuen Block anfordern muss
  • Server 2 fordert Indexblock an.
  • Keyserver liefert (1001,2000)
  • usw...

Man könnte eine ausgefeiltere Version entwickeln, bei der ein Server die Anzahl der benötigten Schlüssel anfordert oder unbenutzte Blöcke an den Keyserver zurückgibt, der dann natürlich eine Karte der benutzten/unbenutzten Blöcke führen müsste.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X