Die harmlos wirkende Anforderung
Es fing mit einer simplen Aufgabe an: Eine AJAX-Abfrage sollte idempotent werden. Konkret bedeutete das — egal wie oft der Request gefeuert wird, das Ergebnis bleibt stabil und vorhersehbar. Kein Flackern, keine Race Conditions, keine doppelten Einträge die sich gegenseitig überholen.
Die klassische Lösung: ORDER BY id. Fertig. Nächstes Problem.
Nur dass es diesmal kein nächstes Problem gab. Zumindest nicht sofort.
Warum ORDER BY id so selbstverständlich funktioniert
Auto-Increment IDs sind im Grunde ein impliziter, kostenloser Zeitstempel — in Zahlenform. Jeder neue Datensatz bekommt eine höhere ID als sein Vorgänger. Das ist durch das Datenbankschema garantiert, nicht durch Konvention oder Absprache.
Das hat drei Vorteile die man erst schätzt wenn sie fehlen:
Erstens ist die Reihenfolge deterministisch. Späterer Eintrag bedeutet immer höhere ID. Keine Ausnahmen.
Zweitens ist der Primary Key per Definition indiziert. ORDER BY id kostet fast nichts — die Datenbank nutzt den ohnehin vorhandenen Index.
Drittens braucht niemand darüber nachzudenken. ORDER BY id ist so selbstverständlich dass es in keinem Code-Review je kommentiert wird.
Der EspoCRM-Moment
EspoCRM ist ein Open-Source-CRM das in vielen Projekten im Einsatz sein soll — und es nutzt UUIDs als Primärschlüssel. Konsequent, durchgehend, überall.
Das ist keine schlechte Entscheidung per se. UUIDs haben ihre Berechtigung: verteilte Systeme, externe API-Anbindungen, Szenarien in denen IDs nie von außen erratbar sein sollen.
Das Problem entstand in dem Moment, in dem die idempotente AJAX-Abfrage auf dieses System traf.
ORDER BY id? Funktioniert nicht wie erwartet. UUIDs sind keine Zahlen — sie werden nicht sequenziell vergeben. Zwei UUIDs verraten nichts darüber welcher Datensatz früher angelegt wurde. Die Reihenfolge ist faktisch zufällig.
Die Workarounds und ihre Tücken
Also weiter suchen. Drei Kandidaten:
ORDER BY name — naheliegend, aber unbrauchbar für diesen Zweck. Namen sind alphabetisch sortierbar, aber kein Mensch kann garantieren dass ein später hinzugefügter Datensatz alphabetisch ans Ende kommt. Die Idempotenz wäre gebrochen sobald jemand einen Eintrag mit „A“ anlegt.
ORDER BY createdAt — das ist die Lösung auf die wir am Ende gesetzt haben. Und sie funktioniert. createdAt wird nur beim Anlegen gesetzt, ändert sich nie, und gibt die chronologische Reihenfolge korrekt wieder.
Aber: Kein Mensch legt auf createdAt einen Index. Warum auch? Niemand denkt beim Anlegen des Schemas daran dass diese Spalte später für Sortierungen gebraucht wird. Für performancekritische Abfragen ist das ein Problem. Auto-Increment ID hätte das kostenlos mitgebracht.
Dazu kommt ein theoretisches, aber reales Risiko: Bei sehr schnellen aufeinanderfolgenden Inserts können zwei Datensätze denselben createdAt-Wert bekommen — je nach Datenbankpräzision. Bei Auto-Increment ist das strukturell ausgeschlossen.
Fazit: Modern ist kein Argument
UUIDs lösen ein echtes Problem — und zwar elegant. Weltweit eindeutige IDs, ohne zentrale Koordination, ohne Kollisionsrisiko. Das ist beeindruckend und in den richtigen Szenarien genau das richtige Werkzeug.
Aber UUIDs haben einen Preis der selten laut ausgesprochen wird.
Menschen können sie nicht lesen. 42 ist eine ID. a3f8c1d2-7e4b-4f9a-b2d1-0c6e5f3a9b7d ist eine Zeichenkette die niemand im Kopf behält. Das klingt nach Kleinigkeit — bis man im Support-Call sitzt, jemanden bittet „schick mir die ID des Eintrags“ und drei Minuten Stille folgen.
Und es macht Lücken unsichtbar. Bei Auto-Increment fällt sofort auf wenn nach ID 41 plötzlich ID 45 kommt. Bei UUIDs? Viel Spaß beim Prüfen ob etwas fehlt.
Dazu kommen ältere Datenbanksysteme die mit UUIDs schlicht langsamer werden — nicht weil sie schlecht sind, sondern weil sie für sequenzielle Integer-Indizes optimiert wurden. UUID-basierte Suchen können je nach System und Datenmenge deutlich teurer sein als ihr Auto-Increment-Äquivalent.
UUIDs haben ihre Berechtigung — wie fast alles in der Softwareentwicklung. Aber „modern“ ist keine Architekturentscheidung. Die Frage ist immer: Was brauche ich wirklich für diesen Anwendungsfall?

Kommentar verfassen