UUIDs als Primärschlüssel in relationalen Datenbanken

PrintFriendly and PDF

Die fortlaufende Datenbank-Id ist vielen Anwendungsentwicklern der liebste technische Primärschlüssel. So komfortabel solche Sequenzen auch sind, sind sie jedoch ein Problem bei der Skalierbarkeit und Replikation von relationalen Datenbanken.

In der relationalen Datenbankwelt mit einem zentralen Datenbankserver sind Sequenzen einfach einzurichten und komfortabel zu verwenden. Fortlaufende Nummern bieten Übersicht in den Datensätzen (von wann stammt der Datensatz ungefähr?) und sind ein schnell auszuwertendes Sortierkriterium.

Wenn jedoch die Skalierbarkeit bzw. Replizierbarkeit einer Datenbank in den Fokus gerät, besitzen Sequenzen auch unangenehme Eigenschaften. Vor allem, wenn es viele parallele Datenbankzugriffe gibt und häufig neue Datensätze angelegt werden. Denn eine Sequenz darf niemals den selben Wert zurückliefern, egal, von wo der Aufruf kommt. In einem Datenbank-Cluster sind Sequenzen daher immer Flaschenhälse für die Skalierbarkeit bzw. gar nicht erst erlaubt.

Interessant ist ein Blick in die NoSQL-Welt. Eine der wichtigsten Eigenschaften der meisten NoSQL-Datenbanken ist die einfache Skalierbarkeit. Dies geht in der Regel auf Kosten einer konsistenten Sicht auf die Daten. Das bedeutet, dass sich Datensätze, die in unterschiedlichen Knoten eines NoSQL-Datenbank-Clusters eingefügt werden, zunächst keine Informationen teilen. Entsprechend gibt es keine zentrale Instanz, die konsistente technische Primärschlüssel verwalten und zuweisen könnte.

Die Dokumentendatenbank CouchDB ist beispielsweise dafür bekannt, Datenbestände so replizieren zu können, dass getrennt vorgenommene Änderungen automatisch wieder zusammengeführt werden können. Dies funktioniert insbesondere auch dann, wenn die Replikas nicht miteinander kommunizieren können. Ein Standardbeispiel dazu ist die auf ein Smartphone replizierte Datenbank, mit der ein Anwender lokal auch ohne Internetverbindung arbeitet. Alle Änderungen am replizierten Datenbestand werden bei nächster Gelegenheit automatisch zurückgespielt.

Wenn es also konzeptuell nicht möglich ist, dass eine zentrale Instanz technische Primärschlüssel verwaltet, sind andere Lösungen gefragt. In der NoSQL-Welt sind vor allem zwei Lösungen verbreitet: anwendungsspezifische, fachliche Primärschlüssel und Unique Universal Identifiers (UUIDs).

UUIDs sind 16 Byte lang und werden hexagonal in Gruppen notiert. Es gibt unterschiedliche Herangehensweisen, UUIDs zu generieren. Es gibt einen Standard, der verschiedene Varianten vorsieht. Die einfachste Variante besteht darin, eine Zufallszahl zu erzeugen. Durch die Größe des Zahlenraums sind doppelt generierte UUIDs sehr unwahrscheinlich. Alternativ stellt man eine UUID aus einem Zeitstempel und einem Knoten zusammen, wo sie erzeugt wurde. Der Knoten besteht üblicherweise aus der MAC-Adresse einer Netzwerkkarte des Rechners. Eine sinnvolle Ergänzung ist die Prozess-ID, um Überschneidungen aus mehreren Prozessen auf einem Rechner zu vermeiden, eventuell ergänzt durch eine prozessinterne, fortlaufende Nummer. Hilfe bei der Generierung von UUIDs bietet die Java-Klasse java.util.UUID. Alternativ gibt es z.B. eine Open-Source UUID-Bibliothek.

Sowohl für handgeschriebene SQL-Anweisungen als auch für die Kommunikation mit einem Fachbereich sind UUIDs sehr unhandlich. Sie bieten aber auch in der relationalen Datenbankwelt Vorteile:

  • Da die UUIDs von der Anwendung erstellt werden, reduziert sich die Anzahl der Datenbankzugriffe. Es müssen keine Sequenzen ausgelesen werden.
  • Jeder Datensatz in jeder Tabelle auf jedem Rechner hat eine eindeutige ID – Fehler, bei Abfragen IDs aus unterschiedlichen Tabellen zu vertauschen, können nicht mehr passieren.
  • Vor allem ermöglichen UUIDs es, Datensätze einfach zu replizieren und getrennte Datenbestände ohne die Gefahr von Überlappungen der IDs zusammenzuführen. Da sich die Ids in getrennten Datenbeständen niemals überschneiden, besteht der vollständige Datenbestand immer aus der Vereinigungsmenge aller getrennten Datenbestände.

Dies ermöglicht es beispielsweise, ähnlich wie bei einer CouchDB, einen zentralen Datenbestand auf ein externes Gerät zu replizieren und dortige Änderungen im Offlinebetrieb wieder zurückzuspielen. Oder es lassen sich Datenbank-Cluster betreiben, die sich nicht innerhalb einzelner Transaktionen konsistent abgleichen, sondern nur innerhalb festgelegter Perioden.

Ob für solche Anwendungsfälle relationale Datenbanken überhaupt noch die richtige Wahl sind, ist eine Frage, die sich nicht allgemein beantworten lässt. Wenn eine relationale Datenbank als Grundlage für eine Anwendung festgelegt worden ist, bieten UUIDs zumindest gewisse Freiheiten, die ansonsten eher im NoSQL-Bereich zu finden sind.