UUID vs. MongoDB ObjectIDs vs. Inkrementelle IDs
Lass uns über IDs in Datenbanken sprechen. Das klingt im ersten Schritt sehr unwichtig, hat allerdings viele verschiedene Faktoren, die zu berücksichtigen sind. Gerade wenn Du dir noch nie Gedanken über Primärschlüssel gemacht hast, solltest Du diesen Artikel lesen.
Bei der Wahl von Primärschlüsseln oder Objekt-IDs in Datenbanken solltest Du vor der Entscheidung stehen: inkrementelle IDs, UUIDs oder datenbankspezifische IDs wie die MongoDB ObjectID.
Die Wahl hat Auswirkungen auf Skalierbarkeit, Sicherheit, Performance und Architektur.
Natürlich gibt es viele verschiedene Arten von IDs. Mittlerweile gibt es von UUIDs 8 verschiedene Versionen. Ich befasse mich daher mit den gängisten Formen, mit denen man am häufigsten in Berührung kommt.
Inkrementelle IDs (1, 2, 3, …)
Eine klassische SQL-Datenbank verwendet häufig Auto-Increment Spalten als Primärschlüssel.
1. Zentrales System
Auto-Increment funktioniert nur zuverlässig, wenn eine zentrale Instanz die nächste ID vergibt.
In verteilten Systemen wird das schwierig:
- Mehrere Datenbank-Writer
- Microservices
- Offline-Synchronisation
- Multi-Region Deployments
Dann benötigt man:
- ID-Server
- Hi/Lo Algorithmus
- Snowflake IDs
- oder andere Workarounds
Das macht die Architektur komplexer.
2. Deterministisch / Vorhersagbar
Wenn ein Nutzer die ID "1000" sieht, hat er bereits zu viele Informationen. Es lässt sich sofort erraten, dass es bereits 999 weitere Benutzer gibt. An dieser Stelle gibst Du bereits wertvolle Informationen preis. Das bringt auch ein Sicherheitsrisiko mit sich.
Es ermöglicht:
- Enumeration Angriffe
- Daten scraping
- Möglichen unautorisierten Zugriff auf fremde Datensätze
3. Objekt existiert erst nach Insert
Bei Auto-Increment entsteht die ID erst beim Insert in die Datenbank.
Das bedeutet:
- Man kann vorher keine Referenzen erstellen
- Kein Offline-Objekt
- Kein Event mit ID vor Persistierung
- Schwieriger bei Event-Sourcing
- Schwieriger bei CQRS
Mit client-generierten IDs existiert das Objekt bereits vor dem Datenbank-Insert.
UUID Version 4
UUIDv4 sind zufällige IDs und sind 128-Bits lang. 4 Bits werden für die Versionsangabe von UUIDs verwendet. 2 weitere Bits werden für eine Unterscheidung der Variante benutzt. Die genaue Aufstellung findest Du im RFC 4122.
1. Nicht vorhersagbar
UUIDs sind zufällig → praktisch nicht zu erraten.
Daher gut für:
- Öffentliche APIs
- URLs
- Multi-Tenant Systeme
- Sicherheit
2. Dezentral generierbar
UUIDs können erzeugt werden:
- Client
- Server
- Worker
- Offline
- Mehrere Services gleichzeitig
Kein zentrales ID-System notwendig.
Perfekt für:
- Microservices
- Event Driven Architecture
- Offline Apps
- Synchronisation
- Multi-Region Systeme
3. Objekt existiert vor dem Insert
Man kann:
- Objekt erstellen
- Events erzeugen
- Referenzen setzen
- Files hochladen
- Logs schreiben
Bevor das Objekt in der Datenbank gespeichert wird.
4. Nachteile von UUIDv4
UUIDv4 sind zufällig → schlecht für Datenbank-Indizes:
- Inserts überall im Index
- Index Fragmentierung
- Größere Indizes
- Langsamere Inserts
- Mehr Storage
- Schlechtere Cache Locality
Deshalb sind UUIDv4 nicht ideal für sehr große Tabellen mit hoher Insert-Rate.
UUID Version 7
UUIDv7 ist relativ neu und kombiniert:
- Timestamp
- Random Bits
Dadurch sind sie:
- Zeitlich sortierbar
- Trotzdem global eindeutig
- Besser für Datenbanken
1. Sortierbarkeit
UUIDv7 steigen zeitlich an → ähnlich wie Auto-Increment, aber verteilt generierbar.
Das verbessert:
- Index Performance
- Insert Geschwindigkeit
- Range Queries
- Pagination
- Log-Events
- Event Stores
2. Bessere Insert Performance
Da neue IDs meist am Ende des Index landen:
- Weniger Index Fragmentierung
- Weniger Page Splits
- Schnellere Inserts
- Bessere Performance bei großen Tabellen
UUIDv7 ist aktuell eine der besten allgemeinen ID-Lösungen.
3. Kombiniert Vorteile
UUIDv7 kombiniert:
- Dezentral generierbar
- Nicht vorhersagbar
- Sortierbar
- Gute DB Performance
- Kein zentrales System
- Geeignet für verteilte Systeme
Viele sehen UUIDv7 als modernen Ersatz für Auto-Increment.
MongoDB ObjectID
MongoDB verwendet standardmäßig eine ObjectID.
Beispiel: 69c13a91590a780b5fa6a740
Die ObjectID besteht aus:
- 4 Bytes Timestamp
- 5 Bytes Random / Machine ID
- 3 Bytes Counter
1. Vorteile
- Zeitlich sortierbar
- Dezentral generierbar
- Gute Insert Performance
- Kein zentrales System
- Enthält Erstellungszeitpunkt
- Funktioniert gut in verteilten Systemen
2. Verrät das Datenbank-System
Wenn jemand eine ObjectID sieht, weiß er sofort → MongoDB wird verwendet
Das kann:
- Architektur offenlegen
- Angriffsfläche geben
- Technologie-Stack verraten
3. Timestamp ist sichtbar
Man kann aus der ID herauslesen:
- Wann wurde das Objekt erstellt
- Reihenfolge von Inserts
- Aktivität des Systems
Je nach Anwendung kann das unerwünscht sein.
4. Nicht Standard
ObjectID ist MongoDB-spezifisch → schlecht, wenn:
- System später migriert wird
- Mehrere Datenbanken verwendet werden
- Daten zwischen Systemen ausgetauscht werden
Kleiner Hinweis: Wenn die IDs applikationsseitig bereits erzeugt werden, kann man das ObjectID-Format auch mit anderen Datenbank-Systemen verwenden. Ähnlich zur Nutzung von UUIDs.
Zusammenfassung - TL;DR
- Jede ID-Variante hat seine Vor- & Nachteile
- Aus heutiger Sicht bietet die UUIDv7 das beste Gesamtpaket aus
- Skalierung
- Sortierbarkeit
- Indexierbarkeit
- (Sicherheit)
- Auch wenn Inkrementelle IDs viele Nachteile mitbringen, gibt es dafür berechtigte Einsatzzwecke