Wie beurteilen Sie die Verwendung von UUIDs als Datenbankzeilenkennungen, insbesondere in Web-Apps?

77

Ich habe es immer vorgezogen, lange Ganzzahlen als Primärschlüssel in Datenbanken zu verwenden, um die Einfachheit und (angenommene) Geschwindigkeit zu gewährleisten. Wenn ich jedoch ein REST- oder Rails-ähnliches URL-Schema für Objektinstanzen verwende, erhalte ich folgende URLs:

http://example.com/user/783

Und dann wird davon ausgegangen, dass es auch Benutzer mit den IDs 782, 781, ..., 2 und 1 gibt. Angenommen, die betreffende Web-App ist sicher genug, um zu verhindern, dass Personen andere Nummern eingeben, um andere Benutzer ohne Berechtigung anzuzeigen. A. Ein einfacher, nacheinander zugewiesener Ersatzschlüssel "verliert" auch die Gesamtzahl der Instanzen (älter als diese), in diesem Fall Benutzer, bei denen es sich möglicherweise um privilegierte Informationen handelt. (Zum Beispiel bin ich Benutzer # 726 im Stackoverflow.)

Wäre eine UUID / GUID eine bessere Lösung? Dann könnte ich URLs wie folgt einrichten:

http://example.com/user/035a46e0-6550-11dd-ad8b-0800200c9a66

Nicht gerade prägnant, aber es werden weniger implizite Informationen über Benutzer angezeigt. Sicher, es riecht nach "Sicherheit durch Dunkelheit", was kein Ersatz für angemessene Sicherheit ist, aber es scheint zumindest ein wenig sicherer zu sein.

Ist dieser Vorteil die Kosten und die Komplexität der Implementierung von UUIDs für webadressierbare Objektinstanzen wert? Ich denke, dass ich immer noch ganzzahlige Spalten als Datenbank-PKs verwenden möchte, um Joins zu beschleunigen.

Es gibt auch die Frage der datenbankinternen Darstellung von UUIDs. Ich weiß, dass MySQL sie als Zeichenfolgen mit 36 ​​Zeichen speichert. Postgres scheint eine effizientere interne Darstellung zu haben (128 Bit?), Aber ich habe es selbst nicht ausprobiert. Hat jemand irgendwelche Erfahrungen damit?


Update: Für diejenigen, die nach der Verwendung des Benutzernamens in der URL gefragt haben (z. B. http://example.com/user/yukondude ), funktioniert dies gut für Objektinstanzen mit eindeutigen Namen, aber was ist mit den Millionen von Web App-Objekte, die wirklich nur anhand der Nummer identifiziert werden können? Bestellungen, Transaktionen, Rechnungen, doppelte Bildnamen, Fragen zum Stapelüberlauf, ...

Yukondude
quelle

Antworten:

34

Ich kann nichts über die Webseite Ihrer Frage sagen. UUids eignen sich jedoch hervorragend für n-Tier-Anwendungen. Die PK-Generierung kann dezentral erfolgen: Jeder Client generiert sein eigenes Paket ohne Kollisionsrisiko. Und der Geschwindigkeitsunterschied ist im Allgemeinen gering.

Stellen Sie sicher, dass Ihre Datenbank einen effizienten Speicherdatentyp unterstützt (16 Byte, 128 Bit). Zumindest können Sie die UUID-Zeichenfolge in base64 codieren und char (22) verwenden.

Ich habe sie ausgiebig mit Firebird verwendet und empfehle sie.

Douglas Tosi
quelle
18
base64? Wenn Sie keinen nativen Datentyp für UUID haben, lassen Sie die Bindestriche fallen und geben Sie das Byte (32) ein. Das ist wahrscheinlich schneller als das Codieren / Decodieren von / zu base64, wenn Sie die UUID benötigen.
CMircea
29

Ich habe gesehen, dass eine lange laufende gespeicherte Prozedur (9+ Sekunden) auf nur einige hundert Millisekunden Laufzeit gesunken ist, indem einfach von GUID-Primärschlüsseln auf Ganzzahlen umgeschaltet wurde. Das heißt nicht, dass das Anzeigen einer GUID eine schlechte Idee ist, aber wie andere betont haben, wird das Zusammenfügen und Indizieren per Definition nicht annähernd so schnell sein wie bei ganzen Zahlen.

Adam Tuttle
quelle
1
Wenn Sie weitere Einzelheiten dazu angeben könnten, wo Sie dies gesehen haben, wäre dies hilfreich. Größe der DB / Tabellen? DB Backend? Zugriffsmuster (wie sah die Abfrage aus) ... usw.?
Garen
12
Wie ist das überhaupt eine Antwort.
Davidahines
16
Es ist ein anekdotischer Beweis, der die mathematische Theorie stützt, dass das Verbinden und Indizieren von ganzen Zahlen schneller ist als lange (ish) Zeichenfolgen.
Adam Tuttle
23

Ich kann Ihnen antworten, dass in SQL Server, wenn Sie einen GUID-Datentyp (Uniqueidentifier) ​​verwenden und die Funktion NEWID () zum Erstellen von Werten verwenden, aufgrund von Seitenteilungen eine schreckliche Fragmentierung auftritt. Der Grund ist, dass bei Verwendung von NEWID () der generierte Wert nicht sequentiell ist. SQL 2005 hat die Funktion NEWSEQUANTIAL () hinzugefügt, um dies zu beheben

Eine Möglichkeit, GUID und int weiterhin zu verwenden, besteht darin, eine Guid und ein Int in einer Tabelle zu haben, damit die Guid dem Int zugeordnet wird. Die Guid wird extern verwendet, die Int intern in der DB

zum Beispiel

457180FB-C2EA-48DF-8BEF-458573DA1C10    1
9A70FF3C-B7DA-4593-93AE-4A8945943C8A    2

1 und 2 werden in Joins und den Guids in der Web-App verwendet. Diese Tabelle ist ziemlich eng und sollte ziemlich schnell abzufragen sein

SQLMenace
quelle
10

Warum sollten Sie Ihren Primärschlüssel mit Ihrer URI koppeln?

Warum sollte Ihr URI-Schlüssel nicht für den Menschen lesbar (oder je nach Ihren Anforderungen nicht erratbar) und Ihre primäre Index-Ganzzahl sein, damit Sie das Beste aus beiden Welten erhalten. Viele Blog-Programme tun dies, bei denen die exponierte ID des Eintrags durch einen "Slug" gekennzeichnet ist und die numerische ID im System versteckt ist.

Der zusätzliche Vorteil hier ist, dass Sie jetzt eine wirklich schöne URL-Struktur haben, die gut für SEO ist. Natürlich ist dies für eine Transaktion keine gute Sache, aber für etwas wie Stackoverflow ist es wichtig (siehe URL oben oben ...). Einzigartigkeit zu erlangen ist nicht so schwierig. Wenn Sie wirklich besorgt sind, speichern Sie irgendwo einen Hash der Schnecke in einer Tabelle und führen Sie vor dem Einfügen eine Suche durch.

edit: Stackoverflow verwendet das von mir beschriebene System nicht ganz, siehe Guys Kommentar unten.

Jonathan Arkell
quelle
8
Stapelüberlaufindizes für die ID und nicht für den Slug. Versuchen Sie, den Slug oben auf der Seite zu ändern, und drücken Sie die Eingabetaste. Sie werden auf der Grundlage der ID (5949) zur kanonischen URL für diese Seite weitergeleitet und der Slug ignoriert. Auf dem Server wird der Slug mit dem gespeicherten / generierten Slug verglichen. Wenn nicht dasselbe, wird ein 301 zurückgegeben. Dies wird jedoch durch Nachschlagen der ID (5949) festgestellt.
Guy
4

Anstelle von URLs wie diesen:

http://example.com/user/783

Warum nicht:

http://example.com/user/yukondude

Was ist für Menschen freundlicher und gibt diese winzigen Informationen nicht preis?

Josh
quelle
Wenn der Spitzname nicht eindeutig ist oder der Buchtitel als Link verwendet und geändert wurde, ist er nicht für SEO- und Benutzer-Lesezeichen geeignet.
ZiiMakc
4

Sie können eine Ganzzahl verwenden, die sich auf die Zeilennummer bezieht, jedoch nicht sequentiell ist. Zum Beispiel könnten Sie die 32 Bits der sequentiellen ID nehmen und sie mit einem festen Schema neu anordnen (zum Beispiel wird Bit 1 zu Bit 6, Bit 2 zu Bit 15 usw.).
Dies ist eine bidirektionale Verschlüsselung, und Sie werden sicher sein, dass zwei verschiedene IDs immer unterschiedliche Verschlüsselungen haben.
Es wäre natürlich leicht zu dekodieren, wenn man sich die Zeit nimmt, genügend IDs zu generieren und das Schema zu erhalten, aber wenn ich Ihr Problem richtig verstehe, möchten Sie Informationen einfach nicht zu einfach weitergeben.

Andrea Bertani
quelle
Ich glaube nicht, dass die Absicht der Frage darin bestand, UUIDs sicher zu verwenden. Soweit ich verstanden habe, waren die praktischen Konsequenzen dieser Entscheidung das Thema. Und Ihr Schema bietet keine Sicherheit und ist eine Verschwendung von CPU-Zyklen!
Patrick Cornelissen
4

Wir verwenden GUIDs als Primärschlüssel für alle unsere Tabellen, da sie gleichzeitig als RowGUID für die MS SQL Server-Replikation fungieren. Macht es sehr einfach, wenn der Kunde plötzlich ein Büro in einem anderen Teil der Welt eröffnet ...

Marius
quelle
3

Ich glaube nicht, dass eine GUID Ihnen viele Vorteile bietet. Benutzer hassen lange, unverständliche URLs.

Erstellen Sie eine kürzere ID, die Sie der URL zuordnen können, oder erzwingen Sie eine eindeutige Benutzernamenkonvention ( http://example.com/user/brianly ). Die Jungs von 37Signals würden dich wahrscheinlich verspotten, weil du dir über so etwas Sorgen machst, wenn es um eine Web-App geht.

Im Übrigen können Sie Ihre Datenbank zwingen, ganzzahlige IDs aus einem Basiswert zu erstellen.

Brian Lyttle
quelle
Dies ist nicht anwendbar. Sie müssen die UUID nicht in der URL anzeigen.
Davidahines
3
@dah der Fragesteller erwähnt die Verwendung innerhalb der URL in der Frage.
Brian Lyttle
3

Dies hängt auch davon ab, was Sie für Ihre Anwendung interessiert. Für n-Tier-Apps sind GUIDs / UUIDs einfacher zu implementieren und einfacher zwischen verschiedenen Datenbanken zu portieren. Um Integer-Schlüssel zu erzeugen, unterstützen einige Datenbanken ein Sequenzobjekt nativ und andere erfordern die benutzerdefinierte Erstellung einer Sequenztabelle.

Ganzzahlige Schlüssel (ich habe keine Zahlen) bieten wahrscheinlich einen Vorteil für die Abfrage- und Indizierungsleistung sowie die Speicherplatznutzung. Direkte DB-Abfragen sind auch mit Zifferntasten viel einfacher, weniger Kopieren / Einfügen, da sie leichter zu merken sind.

Michael Barker
quelle
2

Ich arbeite mit einem Studentenverwaltungssystem, das UUIDs in Form einer Ganzzahl verwendet. Sie haben eine Tabelle, die die nächste eindeutige ID enthält.

Obwohl dies aus architektonischer Sicht wahrscheinlich eine gute Idee ist, erschwert es die tägliche Arbeit. Manchmal müssen Masseneinfügungen vorgenommen werden, und eine UUID macht dies sehr schwierig. In der Regel muss anstelle einer einfachen SELECT INTO-Anweisung ein Cursor geschrieben werden.

GateKiller
quelle
2

Ich habe beides in echten Web-Apps ausprobiert.

Meiner Meinung nach ist es vorzuziehen, ganze Zahlen zu verwenden und kurze, verständliche URLs zu haben.

Als Entwickler fühlt es sich ein bisschen schrecklich an, aufeinanderfolgende Ganzzahlen zu sehen und zu wissen, dass einige Informationen über die Gesamtzahl der Datensätze herauskommen, aber ehrlich gesagt - die meisten Leute kümmern sich wahrscheinlich nicht darum, und diese Informationen waren für mein Unternehmen nie wirklich kritisch.

Lange hässliche UUID-URLs zu haben, scheint mir für normale Benutzer eher ein Ausschalten zu sein.

Daniel Alexiuc
quelle
Danke für diese Meinung. Ich habe tagelang nach UUIDs als Primärschlüssel mit all ihren möglichen Nachteilen gesucht, bis mir klar wurde, dass sich der einzige Vorteil (das Ausblenden von Geschäftsinformationen) in meinem Fall nicht lohnt.
Dr. Jan-Philip Gehrcke
1

Ich denke, dass dies eines dieser Themen ist, die quasi-religiöse Debatten auslösen, und es ist fast sinnlos, darüber zu sprechen. Ich würde nur sagen, verwenden Sie, was Sie bevorzugen. In 99% der Systeme spielt es keine Rolle, welchen Schlüsseltyp Sie verwenden, sodass die Vorteile (in den anderen Beiträgen angegeben) der Verwendung einer Sorte gegenüber der anderen niemals ein Problem darstellen.

Dan
quelle
1

Ich denke, die Verwendung einer GUID wäre in Ihrer Situation die bessere Wahl. Es nimmt mehr Platz ein, ist aber sicherer.

Bryan Roth
quelle
1

Youtube verwendet 11 Zeichen mit Base64-Codierung, die 11 ^ 64 Möglichkeiten bieten, und sie sind normalerweise ziemlich überschaubar zu schreiben. Ich frage mich, ob dies eine bessere Leistung bieten würde als eine vollständige UUID. Die auf Basis 64 konvertierte UUID wäre meiner Meinung nach doppelt so groß.

Weitere Informationen finden Sie hier: https://www.youtube.com/watch?v=gocwRvLhDf8

Sousaplex
quelle
-1

Solange Sie ein DB-System mit effizientem Speicher verwenden, ist die Festplatte heutzutage sowieso billig ...

Ich weiß, dass GUIDs manchmal problemlos funktionieren können und mit einem gewissen Abfrageaufwand verbunden sind, aber aus Sicherheitsgründen sind sie ein Retter.

Wenn Sie an Sicherheit durch Unbekanntheit denken, passen sie gut, wenn Sie obskure URIs bilden und normalisierte DBs mit durch Tabellen, Datensätze und Spalten definierter Sicherheit erstellen. Mit GUIDs können Sie nichts falsch machen. Versuchen Sie dies mit ganzzahligen IDs.

user2106945
quelle