Neue Datenbankstrukturen hinzufügen, ohne laufende Anwendungen zu beeinträchtigen
Sie haben eine users-Tabelle mit einer Spalte full_name. Das Produktteam möchte die Namen in first_name und last_name aufteilen, um eine bessere Personalisierung zu ermöglichen. Sie müssen diese Änderung vornehmen, ohne die Anwendung herunterzufahren oder bestehende Funktionen zu beeinträchtigen.
Der naheliegende Ansatz wäre, full_name zu löschen, die beiden neuen Spalten hinzuzufügen und den gesamten Code auf einmal zu aktualisieren. Das erfordert jedoch koordinierte Deployments, Ausfallzeiten und einen perfekten Rollback-Plan, falls etwas schiefgeht. In der Praxis führen solche Änderungen oft zu nächtlichen Rollbacks und verärgerten Benutzern.
Es gibt einen sichereren Weg: Fügen Sie zuerst die neue Struktur hinzu, ohne die alte anzutasten. Lassen Sie die alte und neue Struktur koexistieren, bis Sie bereit sind, vollständig umzustellen.
Die Expand-Phase: Hinzufügen ohne Entfernen
Das Expand-Contract-Pattern beginnt mit dem sichersten möglichen Schritt. Sie fügen der Datenbank neue Spalten, Tabellen oder Constraints hinzu, während alles, was bereits existiert, völlig unberührt bleibt. Alte Anwendungen, die weiterhin gegen das alte Schema laufen, werden keinen Unterschied bemerken. Neuer Code kann sofort die neuen Strukturen nutzen.
Dies ist der Kern der Expand-Phase: Sie führen neue Datenbankobjekte ein, ohne bestehende zu ändern oder zu entfernen. Das alte Schema bleibt voll funktionsfähig. Das neue Schema ist eine Erweiterung, kein Ersatz.
Das folgende Diagramm zeigt den Zustand der users-Tabelle vor und nach der Expand-Phase sowie die Interaktion alter und neuer Anwendungen mit dem Schema.
Ein konkretes Beispiel
Nehmen Sie die users-Tabelle mit einer full_name-Spalte. In der Expand-Phase fügen Sie zwei neue Spalten hinzu:
Hier ist das SQL zum Hinzufügen der neuen Spalten:
ALTER TABLE users ADD COLUMN first_name VARCHAR(100) NULL;
ALTER TABLE users ADD COLUMN last_name VARCHAR(100) NULL;
ALTER TABLE users ADD COLUMN first_name VARCHAR(100) NULL;
ALTER TABLE users ADD COLUMN last_name VARCHAR(100) NULL;
Die Spalte full_name bleibt genau so, wie sie ist. Alte Anwendungen, die full_name lesen, funktionieren weiterhin ohne Codeänderungen. Neue Anwendungen können in first_name und last_name schreiben, während sie aus Gründen der Abwärtskompatibilität weiterhin full_name lesen.
Keine Ausfallzeiten. Keine koordinierte Veröffentlichung. Kein Risiko, dass bestehende Abfragen fehlschlagen.
Die entscheidende Regel: Neue Spalten müssen optional sein
Der häufigste Fehler in der Expand-Phase ist das Hinzufügen einer neuen Spalte mit NOT NULL und ohne Standardwert. Dies führt sofort dazu, dass jede Anwendung, die Zeilen einfügt, ohne die neue Spalte anzugeben, fehlschlägt. Alte Anwendungen, die nichts von der Existenz der Spalte wissen, werden bei jedem Einfügevorgang scheitern.
Die Regel ist einfach: Jede neue Spalte muss nullbar sein oder einen sinnvollen Standardwert haben. Wenn Sie einen NOT NULL-Constraint benötigen, fügen Sie die Spalte zuerst als nullbar hinzu, füllen Sie die Daten nach und fügen Sie den Constraint in einer späteren Phase hinzu. Zwingen Sie nicht alle vorhandenen Anwendungen, ihre INSERT-Anweisungen gleichzeitig zu ändern.
Die gleiche Logik gilt für neue Tabellen. Eine neue Tabelle ändert keine bestehende Struktur. Alte Anwendungen müssen nie von ihrer Existenz erfahren. Neue Anwendungen können sofort in sie schreiben. Es gibt keinen Konflikt, da sich an den Tabellen, die sie bereits verwenden, nichts geändert hat.
Constraints sicher handhaben
Constraints erfordern während der Expand-Phase besondere Sorgfalt. Wenn Sie einen UNIQUE-Constraint für eine neue Spalte hinzufügen, stellen Sie sicher, dass vorhandene Daten ihn nicht verletzen. Wenn Sie einen FOREIGN KEY hinzufügen, stellen Sie sicher, dass alle vorhandenen Zeilen auf gültige übergeordnete Zeilen verweisen.
Überprüfen Sie bei CHECK-Constraints, dass die Bedingung nicht mit vorhandenen Daten kollidiert. Einige Datenbanken unterstützen eine NOT VALID-Option, die den Constraint nur auf neue Zeilen anwendet und es Ihnen ermöglicht, vorhandene Daten später separat zu validieren. Dies ist nützlich, wenn Sie sich über die Datenqualität in den alten Zeilen nicht sicher sind.
Das Prinzip ist dasselbe: Führen Sie keinen Constraint ein, der bei vorhandenen Daten fehlschlägt. Wenn Sie dies nicht garantieren können, verschieben Sie den Constraint oder fügen Sie ihn so hinzu, dass er Schreibvorgänge nicht blockiert.
Namensgebung ist wichtig
Neue Spalten und Tabellen benötigen klare Namen, die sie von der alten Struktur unterscheiden. Vermeiden Sie Namen wie name_new, temp_name oder name_v2. Diese verursachen Verwirrung in der Contract-Phase, wenn Sie wissen müssen, welche Struktur die kanonische ist.
Verwenden Sie Namen, die die tatsächlichen Daten beschreiben. first_name und last_name sind besser als name_split_1 und name_split_2. Gute Namen erleichtern den Übergang für alle, die später mit dem Schema arbeiten.
Was die Expand-Phase nicht erfordert
Die Expand-Phase erfordert keine Codeänderungen in alten Anwendungen. Sie verwenden weiterhin dasselbe Schema, dieselben Abfragen und dieselbe Logik. Das macht die Expand-Phase sicher, jederzeit ausgeführt zu werden, sogar während der Hauptproduktionszeit.
Keine Ausfallzeiten. Keine Anwendungsneustarts. Keine plötzlich fehlschlagenden Abfragen, weil eine Spalte verschwunden ist. Die einzige Änderung betrifft das Datenbankschema, und diese Änderung ist rein additiv.
Wann die Expand-Phase abgeschlossen ist
Die Expand-Phase ist abgeschlossen, wenn die neuen Strukturen in der Datenbank existieren und einsatzbereit sind. Alte Anwendungen verwenden weiterhin die alten Strukturen. Neue Anwendungen können die neuen Strukturen nutzen. Beide Pfade funktionieren gleichzeitig.
An diesem Punkt haben Sie eine Datenbank, die zwei Versionen des Schemas unterstützt. Dies ist die Grundlage für den nächsten Schritt: die schrittweise Migration von Anwendungen zur Nutzung der neuen Strukturen, ohne etwas zu beeinträchtigen.
Praktische Checkliste für die Expand-Phase
- Neue Spalten sind nullbar oder haben einen Standardwert
- Neue Tabellen ändern keine bestehenden Tabellenstrukturen
- Neue Constraints kollidieren nicht mit vorhandenen Daten
- Namen unterscheiden neue Strukturen klar von alten
- Alte Anwendungen funktionieren ohne Codeänderungen weiter
- Neue Anwendungen können sofort neue Strukturen nutzen
Das Fazit
Die Expand-Phase ist die sicherste Datenbankänderung, die Sie vornehmen können, da sie nur hinzufügt. Kein Entfernen, keine Änderung, kein Risiko, laufende Anwendungen zu beeinträchtigen. Fügen Sie neue Spalten als nullbar hinzu, behalten Sie alte Spalten intakt und lassen Sie beide Schemas koexistieren. Dies gibt Ihnen die Freiheit, Anwendungen in Ihrem eigenen Tempo zu migrieren, ohne einen Big-Bang-Release zu koordinieren oder Ausfallzeiten einzuplanen.