Wie speichere ich UUID als Nummer?

76

Basierend auf der Antwort auf die Frage, die UUID-Leistung in MySQL , schlägt die Person, die antwortet, vor, die UUID als Zahl und nicht als Zeichenfolge zu speichern. Ich bin mir nicht so sicher, wie es gemacht werden kann. Könnte mir jemand etwas vorschlagen? Wie geht mein Ruby-Code damit um?

Chamnap
quelle
5
Die Leistungsprobleme treten nur auf, wenn Sie die UUID als Primärschlüssel verwenden, da UUIDs keine sehr effizienten Primärschlüssel sind. Warum brauchen Sie UUIDs? Könnten Sie die UUIDs behalten und einfach eine automatische Inkrementierung als Primärschlüssel verwenden?
Thom Smith
4
@ThomSmith Re "UUIDs sind keine sehr effizienten Primärschlüssel". Möchten Sie eine Quelle zitieren, die erklärt, warum?
Pacerier
2
Es handelt sich um ein größeres Datenelement, für dessen Vergleich im Allgemeinen mehr Anweisungen erforderlich sind. Es ist nicht sequentiell, daher ist der Aufwand für die Indizierung etwas höher. Und wenn Sie es als Zeichenfolge anstelle einer 128-Bit-Zahl speichern, wie es das OP zu tun scheint, verschlechtert sich die Situation natürlich. Es ist kein schrecklicher Schlüssel, aber ich würde ihn nicht verwenden, wenn es keinen externen Grund dafür gäbe.
Thom Smith
Die automatische Inkrementierung kann Probleme mit mehreren gemeinsam genutzten Datenbankservern verursachen und häufig zu Schlüsselkollisionen führen. UUIDs sollen solche Dinge lösen. Wenn Sie Ihre UUID nicht als Text, sondern als bin (16) speichern, haben Sie natürlich eine numerische UUID. Es ist schneller, Binärdaten als Text zu vergleichen. Hier ist eine Seite, die dies diskutiert - mysql.rjweb.org/doc.php/uuid
Jeff Clayton

Antworten:

108

Wenn ich das richtig verstehe, verwenden Sie UUIDs in Ihrer Primärspalte? Die Leute werden sagen, dass ein regulärer (ganzzahliger) Primärschlüssel schneller ist, aber es gibt eine andere Möglichkeit, die dunkle Seite von MySQL zu nutzen. Tatsächlich verwendet MySQL Binärdateien schneller als alles andere, wenn Indizes erforderlich sind.

Da die UUID 128 Bit beträgt und hexadezimal geschrieben ist, ist es sehr einfach, die UUID zu beschleunigen und zu speichern.

Entfernen Sie zunächst in Ihrer Programmiersprache die Bindestriche

Von 110E8400-E29B-11D4-A716-446655440000bis 110E8400E29B11D4A716446655440000.

Jetzt sind es 32 Zeichen (wie ein MD5-Hash, mit dem dies auch funktioniert).

Da eine Single BINARYin MySQL 8 Bit groß BINARY(16)ist, entspricht sie der Größe einer UUID (8 * 16 = 128).

Sie können einfügen mit:

INSERT INTO Table (FieldBin) VALUES (UNHEX("110E8400E29B11D4A716446655440000"))

und Abfrage mit:

SELECT HEX(FieldBin) AS FieldBin FROM Table

Fügen Sie nun in Ihrer Programmiersprache die Bindestriche an den Positionen 9, 14, 19 und 24 erneut ein, um sie an Ihre ursprüngliche UUID anzupassen. Wenn die Positionen immer unterschiedlich sind, können Sie diese Informationen in einem zweiten Feld speichern.

Vollständiges Beispiel:

CREATE TABLE  `test_table` (
    `field_binary` BINARY( 16 ) NULL ,
    PRIMARY KEY (  `field_binary` )
) ENGINE = INNODB ;

INSERT INTO  `test_table` (
    `field_binary`
)
VALUES (
    UNHEX(  '110E8400E29B11D4A716446655440000' )
);

SELECT HEX(field_binary) AS field_binary FROM `test_table`

Wenn Sie diese Technik mit einer beliebigen Hex-Zeichenfolge verwenden möchten, verwenden Sie immer length / 2die Feldlänge. Für einen sha512 wäre das Feld also, BINARY (64)da eine sha512-Codierung 128 Zeichen lang ist.

David Bélanger
quelle
3
@Chamnap Angenommen, Ihre Datenbank enthält 10 000 Zeilen, die mit der UNHEX-Funktion hinzugefügt wurden, und Sie möchten nach der UUID suchen 110E8400-E29B-11D4-A716-446655440000. Tun Sie einfach etwas wie:SELECT * FROM test_table WHERE field_binary LIKE CONCAT("%", UNHEX('110E8400E29B11D4A716446655440000'), "%")
David Bélanger
5
Sie können dies lesen, wenn Sie Zeit haben. Konzentrieren Sie sich auf Punkt 3: xaprb.com/blog/2009/02/12/…
David Bélanger
4
@Chamnap Ja, das kannst du, du solltest. Ich wollte nur demonstrieren, ob Sie das Zeichen% mit der UNHEX-Funktion in einem LIKE verwenden möchten. Du könntest es tun WHERE Field = UNHEX('110E8400E29B11D4A716446655440000'). Anstatt zu tun WHERE Field = 3oder was auch immer, schließen Sie das Feld mit UNHEX ein, wenn Sie eine Hex-Zeichenfolge verwenden (zum Suchen, Einfügen, Wo, Aktualisieren, Löschen usw.), und Sie schließen das Feld mit HEX ein, wenn Sie aus MySQL lesen möchten (wählen).
David Bélanger
2
@ DavidBélanger Du hast gesagt, MySQL indiziert Binärdateien schneller als Ints. Irgendwelche Quellen?
Pacerier
4
Der Wortlaut ist beim Typ BINARY verwirrend. Ein einzelnes "BINARY" in MySQL hat eine Größe von 8 Bit , weshalb BINARY (16) funktioniert (8 * 16 = 128, die Größe einer UUID). Es wird NICHT "in 1 Bit gespeichert, was hexadezimal in 4 Bit ausgeführt wird". Das ist nicht möglich. "In jeder Einheitsgröße vom Typ BINARY, die selbst 8 Bit groß ist, können zwei hexadezimale Werte gespeichert werden. Wir benötigen also 16 Einheitengrößen von BINARY, daher verwenden wir BINARY (16)."
Lilbyrdie
0

Ich denke nicht, dass es eine gute Idee ist, eine Binärdatei zu verwenden.

Angenommen, Sie möchten einen Wert abfragen:

SELECT HEX(field_binary) AS field_binary FROM `test_table`

Wenn wir mehrere Werte zurückgeben, rufen wir die HEX-Funktion mehrmals auf.

Das Hauptproblem ist jedoch das nächste:

SELECT * FROM `test_table`
    where field_binary=UNHEX('110E8400E29B11D4A716446655440000')

Wenn Sie eine Funktion innerhalb des Where verwenden, wird der Index einfach ignoriert.

Ebenfalls

SELECT * FROM `test_table`
    where field_binary=x'skdsdfk5rtirfdcv@#*#(&#@$9' 

Könnte zu vielen Problemen führen.

Magallane
quelle
1
Haben Sie die Leistung Ihrer Bedenken getestet? Sie schlagen vor, dass die Leistung von HEX und UNHEX schlechter ist als die Leistungsprobleme bei der Verwendung eines Felds mit 36 ​​Zeichen als Index. Ich muss nicht einmal testen, um zu wissen, dass das falsch ist. (Aber da Sie anders glauben, testen Sie) Zweitens ist der Code, den Sie zeigen, nicht, wie dies am besten gehandhabt wird. Ihr gesamter DB-Code sollte einfach das 16-Byte-Feld enthalten. Nicht verhexen und enthexen. Übergeben Sie es einfach als diese 16 Bytes an und von Ihrer Datenbank. Führen Sie alle Abfragen direkt mit diesen 16-Byte-Werten aus. Nur wenn Sie es dem Benutzer anzeigen , müssen Sie es in eine benutzerfreundliche Version konvertieren.
ToolmakerSteve