Wenn Datenbank-Migrationen in der Produktion scheitern: Drei Szenarien, die Ihnen den Schlaf rauben

Sie haben gerade eine Migration in der Produktion ausgeführt. Erfolgreich. Keine Fehler, keine Timeouts, keine gesperrten Tabellen. Sie atmen auf und widmen sich der nächsten Aufgabe.

Zwei Stunden später klingelt Ihr Telefon. Ein Report ist defekt. Daten sehen falsch aus. Ein Service, den Sie vergessen hatten, schreibt NULL-Werte in kritische Tabellen. Die Migration war erfolgreich, aber Ihr Produktionssystem zerfällt.

Das ist der Albtraum von Datenbank-Migrationen. Anders als bei Anwendungs-Deployments, bei denen Fehler meist sofort und offensichtlich sind, können Migrationsfehler stunden- oder tagelang verborgen bleiben. Wenn Sie sie bemerken, hat sich der Schaden bereits ausgebreitet.

Lassen Sie mich drei reale Szenarien zeigen, in denen Migrationen schiefgehen – nicht weil das SQL fehlschlug, sondern weil die Nebenwirkungen alle überraschten.

Szenario Eins: Die neue Spalte, die alles kaputt machte

Ihr Team muss eine Spalte phone_number zur Tabelle users hinzufügen. Die Migration läuft im Staging einwandfrei. Alle Tests bestehen. Sie pushen voller Vertrauen in die Produktion.

Die Spalte wird erstellt. Keine Fehler. Doch Sekunden später zeigt die Anwendung seltsames Verhalten.

Was passiert ist: Die Produktionsanwendung wurde noch nicht aktualisiert. Der alte Code läuft noch und sendet Abfragen wie SELECT * FROM users. Das funktioniert – die neue Spalte wird einfach ignoriert. Das eigentliche Problem liegt woanders. Ein anderer Code beginnt, Daten in phone_number einzufügen, aber in einem anderen Format, als die neue Anwendung erwartet. Telefonnummern kommen in gemischten Formaten – manche mit Ländervorwahl, manche ohne, manche mit Bindestrichen, manche ohne.

Betrachten Sie die Migration, die dieses Szenario auslöste:

ALTER TABLE users ADD COLUMN phone_number VARCHAR(20);

Das sieht harmlos aus. Aber ohne NOT NULL-Constraint oder Standardwert akzeptiert die Spalte jedes Format. Schlimmer noch: Wenn die Tabelle groß ist, sperrt dieses ALTER TABLE die Tabelle für Schreibzugriffe während der gesamten Operation. In der Produktion können sich so in Sekunden Hunderte von Requests stauen. Die eigentliche Gefahr ist nicht das SQL selbst – es ist die Tatsache, dass das Schema geändert wurde, bevor alle Anwendungsinstanzen bereit waren.

Jetzt haben Sie inkonsistente Daten in einer Spalte, auf die mehrere Systeme angewiesen sein werden. Ihr Team steht vor einer unangenehmen Wahl: Entweder die vorhandenen Daten bereinigen oder die neue Anwendungsversion überstürzt in die Produktion bringen, bevor sie fertig ist.

Das Kernproblem ist hier das Timing. Das Schema wurde geändert, bevor der dazugehörige Anwendungscode vollständig ausgerollt war. In einem verteilten System aktualisieren sich nicht alle Instanzen gleichzeitig. Für ein kurzes Zeitfenster – manchmal länger – interagiert alter Code mit dem neuen Schema.

Szenario Zwei: Die Typänderung, die einen nächtlichen Report zerstörte

Dieses Szenario ist subtiler. Ihr Team beschließt, die Spalte price von integer in decimal zu ändern. Gute Idee – Preise brauchen Genauigkeit. Die Migration läuft perfekt. Keine sofortigen Fehler. Die Anwendung scheint zufrieden.

Aber vor sechs Monaten hat jemand eine Report-Abfrage geschrieben, die price als Integer behandelt. Diese Abfrage wird nicht auf den Hauptseiten verwendet. Sie läuft einmal nachts für einen Finanzreport. Um 2 Uhr morgens schlägt der Report komplett fehl. Jede Abfrage, die Preise mit Integer-Werten vergleicht, wirft jetzt Typkonflikte.

Das nennen Ingenieure eine blockierende Änderung. Die Schemaänderung hat tagsüber nichts Sichtbares kaputtgemacht, aber sie hat stillschweigend einen kritischen Batch-Prozess zerstört, der nachts läuft. Am Morgen fragt das Finanzteam, warum die Zahlen von gestern nicht aufgehen.

Das Gefährliche daran? Sie entdecken diesen Fehler vielleicht erst Stunden später. Und die Behebung ist nicht einfach. Sie können den Typ nicht einfach ohne eine weitere Migration zurückändern – und die birgt eigene Risiken.

Szenario Drei: Die gelöschte Spalte, die drei Tabellen vergiftete

Dies ist das gefährlichste Szenario. Ihr Team ist überzeugt, dass die Spalte old_status nicht mehr verwendet wird. Sie wurde vor Monaten als veraltet markiert. Niemand referenziert sie in der Hauptanwendung. Sie schreiben eine Migration, um sie zu löschen.

Die Migration läuft reibungslos. Die Spalte verschwindet. Keine Fehler.

Aber es gibt einen Hintergrundservice – einen Data-Sync-Job, der von einem Team geschrieben wurde, das das Unternehmen vor zwei Jahren verlassen hat – der immer noch regelmäßig old_status liest. Er stürzt nicht ab, wenn die Spalte fehlt. Er beginnt einfach, NULL-Werte in andere Tabellen zu schreiben. Die NULLs breiten sich aus. Die Datenintegrität bricht in den nächsten zwei Stunden stillschweigend über drei verschiedene Tabellen hinweg.

Bis es jemand bemerkt, ist der Schaden angerichtet. Sie können das Löschen der Spalte nicht einfach „rückgängig machen“. Die Daten in den anderen Tabellen sind bereits korrupt. Die Wiederherstellung erfordert, genau zu verstehen, welche Zeilen betroffen waren, die fehlenden Werte aus Backups zu rekonstruieren und sorgfältige Reparatur-Skripte auszuführen.

Warum Datenbank-Migrationen sich von Anwendungs-Deployments unterscheiden

Diese drei Szenarien haben ein gemeinsames Muster: Die Migration wurde erfolgreich ausgeführt, aber die Nebenwirkungen traten später auf. Das macht Datenbank-Migrationen grundlegend anders als Anwendungs-Deployments.

Die drei obigen Szenarien zeigen ein klares Muster: Eine erfolgreiche Schemaänderung löst einen verzögerten Fehler aus. Das folgende Flussdiagramm bildet jedes Szenario von der Ursache bis zur Konsequenz ab.

flowchart TD subgraph Scenario1[Szenario 1: Neue Spalte] A1[phone_number-Spalte hinzufügen] --> B1[Alter Code schreibt inkonsistente Formate] B1 --> C1[Datenkorruption in neuer Spalte] end subgraph Scenario2[Szenario 2: Typänderung] A2[price von integer zu decimal ändern] --> B2[Nächtlicher Report nutzt Integer-Vergleich] B2 --> C2[Report schlägt um 2 Uhr fehl] end subgraph Scenario3[Szenario 3: Gelöschte Spalte] A3[old_status-Spalte löschen] --> B3[Hintergrundservice schreibt NULLs] B3 --> C3[NULLs breiten sich auf 3 Tabellen aus] C3 --> D3[Datenintegrität zerstört] end

Wenn ein Anwendungs-Deployment fehlschlägt, wissen Sie es normalerweise sofort. Fehler erscheinen in Logs. Benutzer melden Probleme. Monitoring-Alarme lösen aus. Sie können die Anwendungsversion zurückrollen und den Dienst schnell wiederherstellen.

Datenbank-Migrationen funktionieren nicht so. Eine Schemaänderung kann:

  • Inkonsistenzen erzeugen, die erst auftreten, wenn neue Daten eintreffen
  • Abfragen zerstören, die nach einem Zeitplan laufen, nicht kontinuierlich
  • Datenkorruption verursachen, die sich langsam über verwandte Tabellen ausbreitet
  • Services betreffen, die Sie vergessen haben oder von denen Sie nichts wussten

Das Schlimmste? Ist der Schaden erst einmal angerichtet, können Sie eine Schemaänderung nicht einfach „rückgängig“ machen wie einen Code-Rollback. Eine gelöschte Spalte lässt sich nicht leicht wiederherstellen, besonders wenn andere Tabellen bereits von ihrem Fehlen abhängen. Ein geänderter Datentyp erfordert eine Rückwärtsmigration, die eigene Risiken birgt.

Eine praktische Checkliste vor Ihrer nächsten Produktions-Migration

Bevor Sie die nächste Migration in der Produktion ausführen, gehen Sie diese Punkte durch:

  • Alle Konsumenten identifizieren. Listen Sie jeden Service, Cron-Job, Report und jede Daten-Pipeline auf, die die betroffene Tabelle berührt. Gehen Sie nicht davon aus, dass Sie alle kennen.
  • Auf verzögerte Ausführung prüfen. Finden Sie Abfragen, die nach Zeitplänen laufen, Batch-Prozesse oder Hintergrund-Jobs. Diese werden stunden später stillschweigend fehlschlagen.
  • Rückwärtskompatibilität prüfen. Kann alter Anwendungscode noch mit dem neuen Schema arbeiten? Für mindestens einen Deployment-Zyklus sollte Ihr Schema sowohl alten als auch neuen Code unterstützen.
  • Wiederherstellungsplan vorbereiten. Wissen Sie genau, wie Sie Daten wiederherstellen, wenn etwas schiefgeht. Testen Sie den Wiederherstellungsprozess, nicht nur die Migration.
  • Migration bei geringem Traffic ausführen. Selbst mit allen Vorsichtsmaßnahmen: Geben Sie sich einen Puffer, um Probleme zu erkennen, bevor sie Benutzer betreffen.

Die konkrete Erkenntnis

Eine erfolgreiche Migration ist nicht eine, die fehlerfrei läuft. Eine erfolgreiche Migration ist eine, die nichts kaputtmacht – weder jetzt, noch in einer Stunde, noch um 3 Uhr morgens, wenn der nächtliche Report läuft. Behandeln Sie jede Schemaänderung als potenzielle Zeitbombe und verifizieren Sie, dass alle Systeme – nicht nur die offensichtlichen – mit der neuen Struktur umgehen können, bevor Sie die Migration als abgeschlossen betrachten.