Wenn auch Ihr Datenbankschema eine Versionskontrolle braucht
Stellen Sie sich vor: Ihr Team hat eine solide CI/CD-Pipeline für den Anwendungscode. Jeder Pull-Request löst automatisierte Tests aus, baut ein Container-Image und deployed auf die Staging-Umgebung. Dann kommt das Produktions-Deployment. Die Pipeline läuft, die Anwendung startet – und stürzt sofort mit einem Column-Not-Found-Fehler ab. Jemand hat vergessen, die Datenbankmigration auszuführen, die die Spalte phone_number hinzufügt. Das Deployment schlägt fehl, Benutzer sehen Fehler, und das Team versucht hektisch herauszufinden, was schiefgelaufen ist.
Dieses Szenario spielt sich täglich in Teams ab. Der Anwendungscode wird versioniert, getestet und über eine Pipeline deployed. Aber die Änderungen am Datenbankschema werden als nachträglicher Einfall behandelt – etwas, das jemand manuell vor oder nach dem Deployment ausführt. Die Diskrepanz zwischen Code-Deployment und Schemaänderungen schafft eine Lücke, durch die Fehler hindurchschlüpfen.
Das Problem: Woher weiß die Pipeline, was bereits ausgeführt wurde?
Wenn Sie ein Verzeichnis mit Migrationsskripten wie V001_create_users.sql, V002_add_phone.sql und V003_add_index.sql haben, muss die Pipeline wissen, welche davon bereits auf die Datenbank angewendet wurden. Sie können nicht bei jedem Deployment alle Dateien von Anfang an ausführen. Die Produktionsdatenbank enthält bereits echte Daten. Die erneute Ausführung von V001 würde entweder fehlschlagen, weil die Tabelle bereits existiert, oder – schlimmer noch – Tabellen löschen und neu erstellen, wodurch Kundendaten verloren gingen.
Ohne einen Nachverfolgungsmechanismus greifen Teams auf manuelle Prüfungen zurück. Jemand meldet sich an der Datenbank an, führt \dt oder SHOW TABLES aus und versucht sich zu erinnern, was letzte Woche deployed wurde. Oder sie verlassen sich auf eine gemeinsame Tabelle, die niemand aktualisiert. Oder sie führen die Migration einfach aus und hoffen auf das Beste.
Keiner dieser Ansätze skaliert. Sie führen zu menschlichen Fehlern, verlangsamen Deployments und erzeugen Angst vor jeder Datenbankänderung.
Die Lösung: Eine Migrationstabelle in der Datenbank
Die Antwort ist überraschend einfach: Lassen Sie die Datenbank ihre eigene Migrationshistorie verfolgen. Erstellen Sie eine spezielle Tabelle, üblicherweise schema_migrations oder migration_history genannt, die jedes ausgeführte Migrationsskript aufzeichnet.
So funktioniert es in der Praxis:
- Wenn ein Migrationstool zum ersten Mal gegen eine leere Datenbank läuft, erstellt es die Migrationstabelle.
- Nachdem jedes Migrationsskript erfolgreich ausgeführt wurde, fügt das Tool eine Zeile mit dem Skriptnamen und dem Zeitstempel der Ausführung ein.
- Bei späteren Deployments liest die Pipeline die Migrationstabelle, vergleicht sie mit der Liste der verfügbaren Migrationsdateien und führt nur die Skripte aus, die noch nicht aufgezeichnet sind.
Nachdem beispielsweise V001_create_users.sql ausgeführt wurde, enthält die Migrationstabelle eine Zeile: V001_create_users.sql. Wenn das nächste Deployment V002_add_phone.sql enthält, überprüft die Pipeline die Tabelle, stellt fest, dass V002 fehlt, und führt es aus. Nach Erfolg wird eine neue Zeile hinzugefügt. Die Datenbank selbst wird zur einzigen Quelle der Wahrheit dafür, welche Version des Schemas derzeit läuft.
Warum das für Ihre Pipeline wichtig ist
Dieser Mechanismus wird als Version Locking bezeichnet. Die Datenbank enthält die maßgebliche Aufzeichnung ihres eigenen Zustands. Es ist keine separate Konfigurationsdatei, keine Umgebungsvariable, die aus dem Takt geraten könnte, und keine manuelle Checkliste erforderlich, die jemand zu aktualisieren vergisst.
Für eine CI/CD-Pipeline ist das entscheidend. Die Pipeline kann nun eine objektive Entscheidung treffen: „Basierend auf dem, was mir die Datenbank sagt, muss ich diese drei Migrationsdateien ausführen.“ Kein Rätselraten, keine manuellen Prüfungen, keine Angst, dieselbe Migration zweimal auszuführen.
Das folgende Sequenzdiagramm veranschaulicht diesen Ablauf:
Verschiedene Migrationstools implementieren dies leicht unterschiedlich. Einige zeichnen eine Prüfsumme jeder Migrationsdatei auf, um zu erkennen, ob jemand ein bereits ausgeführtes Skript modifiziert hat. Andere verwenden sequenzielle Versionsnummern anstelle von Dateinamen. Manche Tools speichern die Migrationshistorie in einem separaten Schema oder einer separaten Datenbank. Aber das Kernprinzip bleibt gleich: Die Datenbank verfolgt ihre eigene Historie, und die Pipeline liest diese Historie, um die nächsten Schritte zu bestimmen.
Bootstrapping: Die erste Migration
Es gibt ein Henne-Ei-Problem. Die Migrationstabelle muss existieren, bevor eine andere Migration aufgezeichnet werden kann. Wie erstellt man sie?
Die meisten Migrationstools erledigen das automatisch. Wenn Sie das Tool zum ersten Mal gegen eine leere Datenbank ausführen, erstellt es die Migrationstabelle im Rahmen seines Bootstrap-Prozesses. Einige Tools zeichnen diese Bootstrap-Aktion sogar als ersten Eintrag in der Migrationshistorie auf.
Wenn Sie Migrationsskripte für eine bestehende Datenbank einführen, die bereits Tabellen und Daten enthält, benötigen Sie einen anderen Ansatz. Hier kommt eine Baseline-Migration ins Spiel. Anstatt zu versuchen, jede historische Änderung nachzubilden, erstellen Sie ein einzelnes Migrationsskript, das den aktuellen Zustand des Datenbankschemas erfasst. Sie markieren dies als Baseline, und das Migrationstool zeichnet es als bereits angewendet auf. Von diesem Zeitpunkt an fügen Sie nur noch neue Migrationsskripte für zukünftige Änderungen hinzu.
Eine Baseline-Migration ist eine pragmatische Lösung. Sie erkennt an, dass man die Geschichte nicht umschreiben kann, aber ab heute Änderungen nachverfolgen kann. Die Alternative wäre, jede jemals vorgenommene Schemaänderung rückzuentwickeln, was für die meisten Teams unpraktikabel ist.
Was die Migrationstabelle nicht löst
Die Migrationstabelle löst ein spezifisches Problem: zu wissen, welche Skripte bereits ausgeführt wurden. Sie gibt der Pipeline eine zuverlässige Möglichkeit, die aktuelle Schema-Version zu bestimmen und ausstehende Änderungen anzuwenden.
Aber sie löst nicht alles. Die Migrationstabelle funktioniert gut für additive Änderungen wie das Hinzufügen von Tabellen, Spalten oder Indizes. Diese Änderungen brechen keinen bestehenden Anwendungscode, der für das alte Schema geschrieben wurde. Die Probleme beginnen, wenn Sie Spalten entfernen oder umbenennen, Datentypen ändern oder Tabellen umstrukturieren müssen. Diese destruktiven oder transformativen Änderungen können laufende Anwendungen unterbrechen, Ausfallzeiten verursachen oder Daten beschädigen.
Die Migrationstabelle sagt Ihnen, was ausgeführt wurde, aber sie sagt Ihnen nicht, ob die laufende Anwendung mit dem neuen Schema kompatibel ist. Dafür sind andere Praktiken erforderlich, wie rückwärtskompatible Migrationen, phasenweise Rollouts und sorgfältige Koordination zwischen Code-Deployment und Schemaänderungen.
Praktische Checkliste für die Migrationsverfolgung
- Wählen Sie ein Migrationstool, das die automatische Verfolgung über eine Migrationstabelle unterstützt.
- Stellen Sie sicher, dass die Migrationstabelle beim ersten Deployment erstellt wird, nicht manuell.
- Ändern Sie niemals ein Migrationsskript, das bereits in der Produktion angewendet wurde.
- Wenn Sie Migrationen für eine bestehende Datenbank einführen, erstellen Sie zuerst eine Baseline-Migration.
- Integrieren Sie die Ausführung von Migrationen als Schritt in Ihre Deployment-Pipeline, nicht als manuellen Prozess.
- Testen Sie Migrationen in einer Staging-Umgebung, die das Datenvolumen der Produktion widerspiegelt.
Die konkrete Erkenntnis
Ihr Datenbankschema ist genauso wichtig wie Ihr Anwendungscode und verdient das gleiche Maß an Versionskontrolle und Automatisierung. Eine Migrationstabelle gibt Ihrer Pipeline eine zuverlässige, datenbankgestützte Möglichkeit zu wissen, was angewendet wurde und was noch ausgeführt werden muss. Ohne sie raten Sie nur. Mit ihr haben Sie eine einzige Quelle der Wahrheit, die die häufigste Ursache für Deployment-Fehler im Zusammenhang mit Datenbankänderungen beseitigt. Beginnen Sie noch heute damit, Ihre Schema-Versionen zu verfolgen – Ihr zukünftiges Ich wird es Ihnen beim nächsten Deployment danken.