it-swarm.com.de

UUID-Leistung in MySQL?

Wir überlegen, UUID-Werte als Primärschlüssel für unsere MySQL-Datenbank zu verwenden. Die eingefügten Daten werden von Dutzenden, Hunderten oder sogar Tausenden von Remotecomputern generiert und mit einer Rate von 100-40.000 Einfügungen pro Sekunde eingefügt, und wir werden keine Aktualisierungen vornehmen.

Die Datenbank selbst wird in der Regel auf etwa 50 Millionen Datensätze zugreifen, bevor mit der Datenauswahl begonnen wird. Dies ist keine massive Datenbank, aber auch keine winzige. Wir planen auch, mit InnoDB zu arbeiten, obwohl wir offen sind, das zu ändern, wenn es einen besseren Motor für das gibt, was wir tun.

Wir waren bereit für die Typ-4-UUID von Java, haben jedoch beim Testen merkwürdiges Verhalten festgestellt. Zum einen speichern wir als varchar (36) und ich weiß jetzt, dass es besser wäre, binär (16) zu verwenden - obwohl ich nicht sicher bin, wie viel besser ist.

Die größere Frage ist: Wie stark vermasseln diese zufälligen Daten den Index, wenn wir 50M-Datensätze haben? Wäre es besser, wenn wir beispielsweise eine UUID vom Typ 1 verwenden würden, bei der die Bits ganz links mit einem Zeitstempel versehen waren? Oder sollten wir UUIDs ganz aufgeben und auto_increment-Primärschlüssel in Betracht ziehen?

Ich bin auf der Suche nach allgemeinen Gedanken/Tipps zur Leistung verschiedener UUID-Typen, wenn diese als Index/Primärschlüssel in MySQL gespeichert werden. Vielen Dank!

70

Eine UUID ist eine universell eindeutige ID. Es ist der universelle Teil, den Sie hier berücksichtigen sollten.

Brauchen Sie wirklich müssen die IDs universell eindeutig sein? Wenn ja, dann können UUIDs Ihre einzige Wahl sein.

Wenn Sie do UUIDs verwenden, sollten Sie sie als Zahl und nicht als Zeichenfolge speichern. Wenn Sie mehr als 50 MB Datensätze haben, verbessert die Einsparung von Speicherplatz Ihre Leistung (obwohl ich nicht sagen konnte, um wie viel).

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

29
Dancrumb

In meinem Job verwenden wir UUID als PKs. Was ich Ihnen aus Erfahrung sagen kann, ist, dass Sie sie NICHT als PKs (übrigens SQL Server) verwenden.

Es ist eines dieser Dinge, wenn Sie weniger als 1000 Datensätze haben, ok, aber wenn Sie Millionen haben, ist es das Schlimmste, was Sie tun können. Warum? Da die UUID nicht sequenziell ist, muss MSSQL jedes Mal, wenn ein neuer Datensatz eingefügt wird, die richtige Seite aufrufen, um den Datensatz einzufügen, und dann den Datensatz einfügen. Die wirklich hässliche Folge ist, dass die Seiten in verschiedenen Größen enden und fragmentiert enden. Jetzt müssen wir die Fragmentierung regelmäßig durchführen.

Wenn Sie ein Autoincrement verwenden, wechselt MSSQL immer zur letzten Seite, und Sie erhalten am Ende gleichgroße Seiten (theoretisch), sodass die Leistung zum Auswählen dieser Datensätze viel besser ist (auch weil die INSERTs die Tabelle/Seite nicht blockieren.) so lange).

Der große Vorteil der Verwendung von UUID als PKs besteht jedoch darin, dass bei Zusammenfügen von DBs keine Konflikte auftreten.

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

Auf diese Weise ist der Zusammenführungsprozess möglich (UUID wäre Ihr REAL-Schlüssel, während der PK nur temporär wäre und eine gute Leistung bringt).

HINWEIS: Die beste Lösung ist die Verwendung von NEWSEQUENTIALID (wie ich in den Kommentaren sagte), aber für ältere Apps, die nicht viel Zeit zum Umgestalten haben (und noch schlimmer, da nicht alle Inserts kontrolliert werden), ist dies nicht möglich. Aber ab 2017 würde ich sagen, die beste Lösung hier ist NEWSEQUENTIALID oder Guid.Comb mit NHibernate.

Hoffe das hilft

66
Kat Lim Ruiz

Zu beachten ist, dass Autoincrements einzeln generiert werden und nicht mit einer parallelen Lösung gelöst werden können. Der Kampf um die Verwendung von UUIDs hängt letztendlich davon ab, was Sie erreichen möchten, und was Sie möglicherweise opfern.

Aufführung, kurz :

Eine UUID wie oben ist 36 Zeichen lang, einschließlich Bindestrichen. Ob Sie speichern diesen VARCHAR (36), Sie sind werde die Leistung des Vergleichs verringern dramatisch. Dies ist dein primäres Schlüssel, Sie wollen nicht, dass es langsam ist.

Auf der Bitebene ist eine UUID 128 Bit, was bedeutet, dass es in 16 Bytes passen wird, Beachten Sie, dass dies nicht sehr gut lesbar ist, aber es wird Speicherplatz niedrig halten 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 .__ funktionieren. viel Aufwand.

Ich empfehle, die folgenden zwei Beiträge zu lesen:

Ich rechne zwischen den beiden, sie beantworten Ihre Frage.

25
Kyle Rozendo

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

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

SAMMLER = EINZIGARTIGER ZUGEWÄHLTER EINER MASCHINE

ID = VON DEM SAMMLER ERFASSTE AUFNAHME (Feld auto_inc)

Das bietet mir zwei Dinge. Geschwindigkeit der Auto-Inc-Felder und Eindeutigkeit der Daten, die an einem zentralen Ort gespeichert werden, nachdem sie gesammelt und gruppiert wurden. Beim Durchsuchen der Daten weiß ich auch, wo sie gesammelt wurden, was für meine Bedürfnisse oft sehr wichtig ist.

Ich habe viele Fälle im Umgang mit anderen Datensätzen für Kunden gesehen, bei denen sie sich für die Verwendung der UUID entschieden haben, aber dann immer noch ein Feld haben, in dem die Daten gesammelt wurden, was wirklich eine Verschwendung von Aufwand ist. Verwenden Sie einfach zwei (oder mehr, falls erforderlich) Felder, da Ihr Schlüssel wirklich hilfreich ist.

Ich habe gerade zu viele Performance-Hits mit UUID gesehen. Sie fühlen sich wie ein Betrüger ...

5

Anstatt zentral eindeutige Schlüssel für jede Einfügung zu generieren, können Sie den einzelnen Servern Schlüsselblöcke zuweisen. Wenn die Schlüssel ausgehen, können sie einen neuen Block anfordern. Dann lösen Sie das Problem des Overheads, indem Sie für jeden Einsatz eine Verbindung herstellen.

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

  • Server 1 fordert ID-Block an.
  • Keyserver kehrt zurück (1,1000)
    Server 1 kann 1000 Datensätze einfügen, bis ein neuer Block angefordert werden muss
  • Server 2 fordert Indexblock an.
  • Keyserver kehrt zurück (1001,2000)
  • usw...

Sie könnten eine ausgefeiltere Version entwickeln, bei der ein Server die Anzahl der benötigten Schlüssel anfordern oder nicht verwendete Blöcke an den Keyserver zurückgeben kann, der dann natürlich eine Karte der verwendeten/nicht verwendeten Blöcke benötigt.

3
Bouke Versteegh

Ich würde jedem Server auf transaktionsmäßige Weise eine numerische ID zuweisen. Dann wird jeder eingefügte Datensatz seinen eigenen Zähler automatisch eininkrementieren. Die Kombination von ServerID und RecordID wird eindeutig sein .. Das ServerID-Feld kann indiziert werden und in Zukunft Wählen Sie die Leistung .__ basierend auf der ServerID (falls erforderlich) aus.

2
Nikolai

Was ist mit einer handgefertigten UID? Vergeben Sie jedem der Tausenden von Servern eine ID und machen Sie aus dem Primärschlüssel einen Kombinationsschlüssel aus Autoincrement, MachineID ???

1
MindStalker

Da der Primärschlüssel dezentral generiert wird, können Sie ohnehin kein auto_increment verwenden.

Wenn Sie die Identität der Remote-Computer nicht verbergen müssen, verwenden Sie UUIDs vom Typ 1 anstelle von UUIDs. Sie sind einfacher zu generieren und können die Performance der Datenbank zumindest nicht beeinträchtigen.

Das gleiche gilt für varchar (char, wirklich) und binär: Es kann nur helfen. Ist es wirklich wichtig, wie viel Leistung verbessert wird?

1
user3850

Die kurze Antwort ist, dass viele Datenbanken (insbesondere bei hohen INSERT-Volumes) aufgrund eines Konflikts zwischen ihrer Indizierungsmethode und der absichtlichen Entropie der UUIDs in den höherwertigen Bits Leistungsprobleme aufweisen. Es gibt mehrere häufige Hacks:

  • wählen Sie einen anderen Indextyp (z. B. nicht in MSSQL geclustert), der es nicht stört
  • munge die Daten, um die Entropie zu Bits niedrigerer Ordnung zu verschieben (z. B. Umordnen von Bytes von V1-UUIDs in MySQL)
  • machen Sie die UUID zu einem Sekundärschlüssel mit einem Auto-Inkrement-Int-Primärschlüssel

... aber das sind alles Hacks - und wahrscheinlich auch zerbrechliche.

Die beste, aber leider die langsamste Antwort ist, dass Ihr Hersteller sein Produkt verbessert, damit UUIDs wie jeder andere Typ als Primärschlüssel verwendet werden können. Sie sollten Sie nicht dazu zwingen, Ihren eigenen halbgebackenen Hack zu würfeln, um das Versäumnis zu lösen, das zu lösen, was zu einem häufigen Anwendungsfall geworden ist und nur weiter wachsen wird.

0
StephenS