UUID Generator

UUID v4 vs v7 Vergleich: Wann welche verwenden

Unterschiede zwischen UUID v4 (zufällig) und v7 (zeitlich geordnet). Bit-Struktur, Auswirkungen auf die B-Tree-Leistung, Vergleich mit ULID und Anwendungsfälle.

100% clientseitig. Deine Daten verlassen niemals deinen Browser.

Verwandte Werkzeuge

Zusammenfassung von UUID v4 und v7

Sowohl UUID v4 als auch v7 sind 128-Bit-Kennungen, formatiert als 32 hexadezimale Zeichen, gruppiert als 8-4-4-4-12. Der Unterschied liegt im Inhalt dieser Bits.

Eine UUID v4 sieht so aus:

f47ac10b-58cc-4372-a567-0e02b2c3d479
         ^^^^
         Versionsnibble = 4

Eine UUID v7 sieht so aus:

018e2b3c-d4a1-7f2e-b8c9-1234567890ab
^^^^^^^^^^^^^
48 Bits Zeitstempel ms
              ^
              Versionsnibble = 7

Dieser strukturelle Unterschied hat reale Leistungsauswirkungen für Datenbanken.

UUID v4: Struktur

UUID v4 reserviert 122 Bits für Zufälligkeit. Die restlichen 6 Bits sind reserviert:

xxxxxxxx-xxxx-4xxx-[89ab]xxx-xxxxxxxxxxxx

Die x-Zeichen sind zufällig. Das 13. Zeichen ist immer 4. Das 17. Zeichen ist immer eines von 8, 9, a oder b.

Die Erzeugung ist in den meisten Sprachen ein einziger Aufruf:

import uuid
str(uuid.uuid4())
# 'f47ac10b-58cc-4372-a567-0e02b2c3d479'
crypto.randomUUID()  // nativ seit Node 14.17 / alle modernen Browser
# 'f47ac10b-58cc-4372-a567-0e02b2c3d479'
import "github.com/google/uuid"
uuid.New().String()

UUID v7: Struktur

UUID v7, standardisiert in RFC 9562 (Mai 2024), verwendet die ersten 48 Bits für einen Unix-Zeitstempel in Millisekunden, gefolgt von Versionsbits und zufälligen Daten:

[48 Bits Zeitstempel ms][4 Bits Version = 7][12 Bits zufällig][2 Bits Variante][62 Bits zufällig]

Das 48-Bit-Zeitstempel-Präfix bedeutet, dass UUIDs, die in derselben Millisekunde erzeugt werden, in ihren höchstwertigen Bits nahezu identisch sind, und später erzeugte UUIDs sind lexikografisch größer. Dies ist die Eigenschaft, die v7 B-Tree-freundlich macht.

# Python 3.11+ hat uuid7 nativ in der Standardbibliothek
import uuid
str(uuid.uuid7())  # Python 3.11+
// Noch keine native Unterstützung, verwende eine Bibliothek
import { v7 as uuidv7 } from 'uuid';
uuidv7()
// '018e2b3c-d4a1-7f2e-b8c9-1234567890ab'
// Java hat kein natives UUID v7, verwende java-uuid-generator
import com.fasterxml.uuid.Generators;
Generators.timeBasedEpochRandomGenerator().generate().toString();

Warum zufällige UUIDs die Datenbankleistung beeinträchtigen

B-Tree-Indizes (verwendet von PostgreSQL, MySQL, SQL Server und den meisten anderen) halten eine sequenzielle Ordnung aufrecht. Wenn du eine neue Zeile einfügst, findet die Datenbank, wo der neue Schlüssel in den sortierten Index gehört, und platziert ihn dort.

Bei UUID v4 sind neue Schlüssel gleichmäßig zufällig über den gesamten 128-Bit-Raum verteilt. Der neue Schlüssel gehört fast nie ans Ende des Index. Die Datenbank muss:

  1. Die Indexseite lesen, zu der der Schlüssel gehört
  2. Wenn die Seite voll ist, teile sie auf (eine neue Seite zuweisen und Einträge neu verteilen)
  3. Übergeordnete Indexknoten aktualisieren

Bei hohen Einfügeraten verursacht dies ständige Seitenteilungen, hohe Schreibverstärkung und geringe Cache-Auslastung. Indexseiten werden aus dem Buffer Pool entfernt, sobald sie geschrieben wurden, weil neue Einfügungen fast nie dieselbe Seite zweimal treffen.

Bei UUID v7 sind neue Schlüssel immer größer als alle vorherigen Schlüssel (innerhalb derselben Millisekunde). Die Einfügungen gehen zur Blattseite ganz rechts im B-Tree. Die Seiten werden sequenziell gefüllt, Teilungen sind selten und die aktiven Seiten bleiben im Buffer Pool.

Der Unterschied ist messbar. Benchmarks in PostgreSQL mit UUID-v4- vs. v7-Primärschlüsseln zeigen typischerweise 20 bis 50% besseren Einfügungsdurchsatz für v7 bei großen Tabellen, bei deutlich geringerem Index-Bloat.

Wann welche Version verwenden

Verwende UUID v4, wenn:

Verwende UUID v7, wenn:

UUID v7 vs ULID

ULID (Universally Unique Lexicographically Sortable Identifier) löst dasselbe Problem wie UUID v7 (sortierbare, zeitlich geordnete IDs) mit einem anderen Format. ULIDs verwenden 48-Bit-Zeitstempel in Millisekunden und 80 Bits Zufälligkeit, kodiert als 26 Crockford-Base32-Zeichen (z.B. 01ARZ3NDEKTSV4RRFFQ69G5FAV).

Der praktische Unterschied ist die Formatkompatibilität. Wenn dein System UUID-formatierte Strings erwartet (36 Zeichen, hex, mit Bindestrichen), verwende UUID v7. Wenn du kürzere, URL-sichere Kennungen möchtest und das Format durchgängig kontrollierst, ist ULID eine vernünftige Wahl. Beide sind nach Erzeugungszeit geordnet; beide vermeiden das B-Tree-Problem.

UUID v7 hat den Vorteil, ein IETF-Standard (RFC 9562) zu sein, was bedeutet, dass die Ökosystemunterstützung schnell wächst.

UUID-Versionen in der Praxis identifizieren

Bei einem gegebenen UUID-String steht die Version immer an Position 14 (0-indexiert), das erste Zeichen der dritten Gruppe:

xxxxxxxx-xxxx-Vxxx-xxxx-xxxxxxxxxxxx
              ^
              Position 14, immer die Versionsziffer

Die Variante steht an Position 19 (das erste Zeichen der vierten Gruppe): 8, 9, a oder b für RFC-4122-UUIDs. Wenn du eine 0 oder f an Position 14 siehst, ist der Wert wahrscheinlich keine Standard-UUID. Es könnte eine Null-UUID, eine Max-UUID oder ein nicht-standardmäßiger Bezeichner im UUID-Format sein.