Vorbereitungen, Checks, Rollback
Schema-Änderungen in Produktionsdatenbanken sind riskant — aber mit der richtigen Vorbereitung, den richtigen Werkzeugen und einem klaren Rollback-Plan sind sie beherrschbar.
Inhaltsverzeichnis
- Pre-Migration-Checkliste: Backup, Replikations-Lag und Disk Space
- ALTER TABLE in MySQL: Warum es in der Produktion riskant ist
- gh-ost: GitHub's Online Schema Change Tool
- pt-online-schema-change: Trigger-basierter Ansatz
- Backward-Compatible Migration Pattern: Expand/Contract
- Magento db_schema.xml: Deklarative Schema-Verwaltung
- Migrationen auf Produktionsgröße testen
- Rollback-Strategien: Forward-Only vs. Rollback-Migrations
- Migration überwachen: Fortschritt und Sperren
- Zusammenfassung
- FAQ
Pre-Migration-Checkliste: Backup, Replikations-Lag und Disk Space
Bevor irgendeine Schema-Änderung auf einer Produktionsdatenbank ausgeführt wird, ist eine standardisierte Checkliste das wichtigste Sicherheitsnetz. Diese Checkliste ist keine Formalität, sondern eine echte Absicherung gegen die häufigsten Katastrophenszenarien bei Datenbank-Migrationen.
Der erste Schritt ist immer ein vollständiges Backup. Für InnoDB-Tabellen ist mysqldump --single-transaction die bevorzugte Methode für konsistente Backups ohne Tabellensperren. Das --single-transaction-Flag startet eine Transaktion mit REPEATABLE READ, sodass alle Tabellen in einem konsistenten Zustand gesichert werden, während die Datenbank weiterhin schreibbar bleibt.
Der zweite Check ist der Replikations-Lag. Wenn der MySQL-Server ein Replikationssetup hat (Primary/Replica), muss der Lag vor der Migration nahezu null sein. Eine Schema-Änderung auf dem Primary wird auf den Replicas sequentiell angewandt — wenn schon ein Lag besteht, werden Replicas durch die Migration weiter zurückfallen und möglicherweise für lesende Anfragen unbrauchbar.
Der dritte Check ist der verfügbare Disk Space. Sowohl ALTER TABLE als auch gh-ost und pt-osc brauchen temporären Speicherplatz in der Größenordnung der zu ändernden Tabelle. Bei einer 50-GB-Tabelle werden mindestens 50 GB freier Speicherplatz benötigt.
-- Step 1: Create a full backup before any schema change
-- Use --single-transaction for InnoDB (no table locks, consistent snapshot)
-- Run OUTSIDE MySQL, in the shell:
-- mysqldump --single-transaction --routines --triggers \
-- -h hostname -u username -p database_name > backup_$(date +%Y%m%d_%H%M%S).sql
-- Step 2: Check replication lag on the replica
-- Run on the REPLICA server (not primary):
SHOW REPLICA STATUS\G
-- Key field: Seconds_Behind_Source (should be 0 or near-0 before migrating)
-- If > 30 seconds: wait and investigate before proceeding
-- Step 3: Estimate table size before migration
SELECT
table_name,
table_rows,
ROUND(data_length / 1024 / 1024, 0) AS data_mb,
ROUND(index_length / 1024 / 1024, 0) AS index_mb,
ROUND((data_length + index_length) / 1024 / 1024, 0) AS total_mb
FROM information_schema.TABLES
WHERE table_schema = DATABASE()
AND table_name = 'sales_order'
ORDER BY total_mb DESC;
-- Step 4: Check available disk space
-- Run in the shell:
-- df -h /var/lib/mysql
-- Ensure at least 2x the table size is available for online schema change tools
ALTER TABLE in MySQL: Warum es in der Produktion riskant ist
Ein einfaches ALTER TABLE ist in der Entwicklungsumgebung das selbstverständlichste der Welt. In der Produktion auf einer großen Tabelle kann dasselbe Statement zur Katastrophe werden. Das liegt an der Art, wie MySQL ältere ALTER TABLE-Operationen implementiert: In MySQL 5.x musste MySQL für viele Typen von Schemaänderungen die gesamte Tabelle Zeile für Zeile in eine neue Struktur kopieren. Während dieser Operation hielt MySQL eine exklusive Schreibsperre auf die Tabelle — der Shop war faktisch nicht schreibbar.
In MySQL 5.6 und 8.0 wurde das In-Place-ALTER eingeführt, das viele Änderungen ohne vollständige Tabellenkopie durchführen kann. Aber nicht alle Operationen sind in-place: Spalten-Umbenennungen, Typ-Änderungen, das Hinzufügen von NOT NULL zu einer existierenden Spalte, bestimmte Indexoperationen — all das erfordert noch immer eine vollständige Tabellenkopie. Für Tabellen mit Millionen von Zeilen kann das Stunden dauern.
gh-ost: GitHub's Online Schema Change Tool
gh-ost (GitHub's Online Schema Changer) ist das modernste und sicherste Tool für Online-Schema-Änderungen in MySQL. Im Gegensatz zu trigger-basierten Ansätzen verwendet gh-ost das MySQL-Binärlog als Grundlage: Es erstellt eine Shadow-Tabelle mit dem neuen Schema, streamt Änderungen vom Binärlog in die Shadow-Tabelle und kopiert gleichzeitig bestehende Daten in Chunks. Wenn Shadow-Tabelle und Originaltabelle synchron sind, wird ein schneller Austausch (atomic rename) durchgeführt.
Der Schlüsselvorteil von gh-ost ist, dass es keine Trigger auf der Quelltabelle anlegt. Trigger können unter hoher Last zu erheblichem Write-Overhead führen und sind bei Replikationssetups manchmal problematisch. Da gh-ost über das Binärlog arbeitet, ist die Auswirkung auf den laufenden Betrieb deutlich geringer.
gh-ost bietet außerdem eine einzigartige "Pause"-Funktion: Wenn die Last auf der Datenbank während der Migration zu hoch wird, kann gh-ost pausiert und zu einem späteren Zeitpunkt fortgesetzt werden. Das macht es ideal für Migrationen auf Produktionssystemen mit variablem Traffic.
-- gh-ost is run from the command line (not within MySQL)
-- Example: Add a new nullable column to customer_entity
-- Run in shell (replace with actual connection details):
-- gh-ost \
-- --host=127.0.0.1 \
-- --port=3306 \
-- --user=migration_user \
-- --password=secret \
-- --database=magento \
-- --table=customer_entity \
-- --alter="ADD COLUMN loyalty_points INT NULL DEFAULT NULL AFTER is_active" \
-- --allow-on-master \
-- --chunk-size=500 \
-- --max-load=Threads_running=25 \
-- --critical-load=Threads_running=100 \
-- --switch-to-rbr \
-- --exact-rowcount \
-- --verbose \
-- --execute
-- Monitor gh-ost progress via its interactive socket:
-- echo "status" | nc -U /tmp/gh-ost.customer_entity.sock
-- The shadow table gh-ost creates during migration (not to be confused with the final table):
-- _customer_entity_gho (the new table being built)
-- _customer_entity_ghc (the changelog table for tracking changes)
-- After migration: verify the new column exists
SHOW COLUMNS FROM customer_entity LIKE 'loyalty_points';
pt-online-schema-change: Trigger-basierter Ansatz
pt-online-schema-change (pt-osc) aus dem Percona Toolkit ist das ältere, aber immer noch weit verbreitete Werkzeug für Online-Schema-Änderungen. Es funktioniert anders als gh-ost: pt-osc legt auf der Originaltabelle Trigger an (INSERT, UPDATE, DELETE), die alle Änderungen synchron auf eine Shadow-Tabelle mit dem neuen Schema weiterleiten. Gleichzeitig kopiert pt-osc die bestehenden Daten in Chunks in die Shadow-Tabelle.
Der Vorteil von pt-osc ist die einfachere Konfiguration und die Eignung für kleinere bis mittlere Tabellen (bis einige Gigabyte). Bei sehr großen Tabellen oder unter sehr hoher Write-Last können die Trigger zu erheblichem Overhead führen. Für Magento-Tabellen wie sales_order_item oder catalog_product_flat_1, auf denen intensiv geschrieben wird, ist gh-ost die bessere Wahl.
-- pt-online-schema-change is run from the shell
-- Example: Add an index to sales_order without table locks
-- pt-online-schema-change \
-- --host=127.0.0.1 \
-- --user=migration_user \
-- --password=secret \
-- --alter="ADD INDEX idx_store_status_date (store_id, status, created_at)" \
-- --chunk-size=1000 \
-- --sleep=0.1 \
-- --progress=percentage,1 \
-- --execute \
-- D=magento,t=sales_order
-- After pt-osc migration: verify the index was created
SHOW INDEX FROM sales_order WHERE Key_name = 'idx_store_status_date'\G
-- Check for leftover trigger names (should not exist after successful migration):
SELECT trigger_name, event_manipulation, action_statement
FROM information_schema.TRIGGERS
WHERE trigger_schema = 'magento'
AND event_object_table = 'sales_order';
Backward-Compatible Migration Pattern: Expand/Contract
Das Expand/Contract-Muster (auch "Blue-Green Schema Migration" genannt) ist die sicherste Strategie für Zero-Downtime-Deployments, bei denen Anwendungs-Code und Datenbankschema gleichzeitig geändert werden müssen. Das Problem: Wenn Schema und Code gleichzeitig deployed werden, gibt es immer einen Moment, in dem alte Code-Version gegen neue Schema-Version läuft oder umgekehrt.
Die Lösung ist eine dreistufige Migration. Phase 1 (Expand): Die neue Spalte wird als nullable hinzugefügt. Die alte Spalte bleibt bestehen. Der Code wird deployed und schreibt ab sofort in beide Spalten. Phase 2 (Migrate): Ein Hintergrund-Job füllt die neue Spalte für alle existierenden Zeilen. Phase 3 (Contract): Wenn alle Zeilen migriert sind, wird die NOT NULL-Constraint zur neuen Spalte hinzugefügt und die alte Spalte entfernt.
-- EXPAND/CONTRACT PATTERN for zero-downtime column rename/type change
-- === PHASE 1: EXPAND ===
-- Add new nullable column alongside the existing one
-- No app changes needed yet; both columns coexist
ALTER TABLE customer_entity
ADD COLUMN loyalty_tier VARCHAR(20) NULL DEFAULT NULL;
-- Application is deployed in "dual-write mode": writes to both old and new column
-- === PHASE 2: BACKFILL ===
-- Fill new column for existing rows in small batches (avoid locking full table)
-- Run this as a background process or scheduled job
UPDATE customer_entity
SET loyalty_tier = CASE
WHEN loyalty_points >= 1000 THEN 'gold'
WHEN loyalty_points >= 500 THEN 'silver'
ELSE 'bronze'
END
WHERE loyalty_tier IS NULL -- only rows not yet migrated
LIMIT 5000;
-- Repeat until 0 rows updated
-- Verify backfill is complete:
SELECT COUNT(*) FROM customer_entity WHERE loyalty_tier IS NULL;
-- Should return 0 before proceeding to Phase 3
-- === PHASE 3: CONTRACT ===
-- Add NOT NULL constraint now that all rows are populated
ALTER TABLE customer_entity
MODIFY COLUMN loyalty_tier VARCHAR(20) NOT NULL DEFAULT 'bronze';
-- Deploy app version that reads from new column only
-- Then drop the old column (after confirming app no longer uses it)
ALTER TABLE customer_entity DROP COLUMN loyalty_points;
Magento db_schema.xml: Deklarative Schema-Verwaltung
Magento 2.3+ verwendet das deklarative Schema-System mit db_schema.xml-Dateien. Statt imperativer InstallSchemas oder UpgradeSchemas beschreibt man in XML den gewünschten Zielzustand des Schemas, und Magento berechnet selbst das Delta zwischen aktuellem und gewünschtem Zustand. Dieses Vorgehen ist deutlich wartbarer und vermeidet die bekannten Probleme der alten Install/Upgrade-Script-Kette.
Der Befehl bin/magento setup:upgrade vergleicht die bestehende db_schema_whitelist.json mit dem aktuellen Schema und führt die notwendigen Änderungen aus. Für größere Tabellen empfiehlt es sich, die Änderungen in db_schema.xml backward-kompatibel zu gestalten (nullable zuerst, dann NOT NULL in einem separaten Deployment) und bei sehr großen Tabellen auf gh-ost auszuweichen, statt den nativen setup:upgrade-Mechanismus zu verwenden.
-- db_schema.xml is XML, but the actual DDL that Magento generates can be inspected:
-- Run: bin/magento setup:db-declaration:generate-whitelist --module-name=Vendor_Module
-- Check what changes setup:upgrade WOULD apply (dry run):
-- bin/magento setup:upgrade --dry-run
-- After setup:upgrade: verify schema was applied correctly
DESCRIBE customer_entity;
-- Check Magento's schema version tracking
SELECT schema_id, origin, type, module, data_version
FROM setup_module
WHERE module LIKE '%Customer%'
ORDER BY module;
-- Magento's declarative schema stores what it knows about the DB in:
SELECT table_name, column_name, column_type, is_nullable, column_default
FROM information_schema.COLUMNS
WHERE table_schema = DATABASE()
AND table_name = 'customer_entity'
ORDER BY ordinal_position;
Migrationen auf Produktionsgröße testen
Eine der häufigsten Ursachen für fehlgeschlagene Produktions-Migrationen ist das Testen auf zu kleinen Datenmengen. Eine Migration, die auf einem 100-MB-Dump in 30 Sekunden läuft, kann auf einem 50-GB-Produktionsdump 8 Stunden dauern. Der wichtigste Grundsatz: Migrationen immer zuerst auf einer Kopie der Produktionsdatenbank in Produktionsgröße testen.
Ein weiterer kritischer Test ist die Belastung während der Migration. gh-ost und pt-osc sind so designed, dass sie die Produktionslast minimieren, aber unter dem tatsächlichen Traffic-Profil des Shops verhält sich die Migration möglicherweise anders als im Labor. Am besten führt man den Test auf einer Staging-Umgebung durch, die mit realem Traffic (oder einer Last-Simulation) belastet wird.
Rollback-Strategien: Forward-Only vs. Rollback-Migrations
Es gibt zwei grundlegende Philosophien für den Umgang mit Migrations-Fehlern. Die "Forward-Only"-Philosophie besagt, dass Migrationen nie rückgängig gemacht werden, sondern dass Fehler durch neue Migrationen in Vorwärtsrichtung behoben werden. Das ist die Philosophie hinter Tools wie Flyway und Liquibase und entspricht auch der Philosophie des Magento-Patch-Systems.
Die Alternative sind explizite Rollback-Migrationen: Für jede Migration gibt es eine Down-Migration, die den Zustand umkehrt. Das klingt attraktiv, ist aber in der Praxis schwieriger als gedacht: Wenn eine Migration Daten transformiert hat (z.B. eine Spalte aufgeteilt oder Werte umgeschlüsselt hat), ist eine verlustlose Umkehrung oft nicht möglich.
Die pragmatische Empfehlung für Produktionssysteme: Verwende das Backward-Compatible Expand/Contract-Muster. Wenn jede Migration-Phase backward-kompatibel ist, gibt es keinen Moment, an dem ein Rollback des Codes zu einem Datenbankfehler führt. Das macht explizite Rollback-Migrationen weitgehend unnötig.
Migration überwachen: Fortschritt und Sperren
Während einer laufenden Migration ist es wichtig, zwei Dinge gleichzeitig zu überwachen: den Fortschritt der Migration selbst und den Einfluss auf den laufenden Betrieb. Wichtige Metriken sind: aktive Verbindungen, Wartezeiten auf Sperren (lock waits), Replikations-Lag und I/O-Auslastung.
-- Monitor active connections and their state during migration
SELECT
id,
user,
host,
db,
command,
time,
state,
LEFT(info, 80) AS query_preview
FROM information_schema.PROCESSLIST
WHERE command != 'Sleep'
ORDER BY time DESC
LIMIT 20;
-- Check for lock waits that indicate migration is blocking other queries
SELECT
r.trx_id AS waiting_trx_id,
r.trx_mysql_thread_id AS waiting_thread,
r.trx_query AS waiting_query,
b.trx_id AS blocking_trx_id,
b.trx_mysql_thread_id AS blocking_thread,
b.trx_query AS blocking_query
FROM information_schema.INNODB_LOCK_WAITS AS w
JOIN information_schema.INNODB_TRX AS r ON r.trx_id = w.requesting_trx_id
JOIN information_schema.INNODB_TRX AS b ON b.trx_id = w.blocking_trx_id;
-- Monitor replica lag during migration (run on replica):
SHOW REPLICA STATUS\G
-- Watch: Seconds_Behind_Source — should stay below acceptable threshold
-- Check InnoDB buffer pool dirty pages (high during large migrations):
SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_pages_dirty';
SHOW GLOBAL STATUS LIKE 'Innodb_os_log_pending_fsyncs';
Mironsoft · MySQL & Magento
Datenbank-Migrationen sicher planen und durchführen
Wir begleiten Schema-Änderungen auf Produktionsdatenbanken: Pre-Migration-Analyse, gh-ost-Setup, Expand/Contract-Planung und Rollback-Strategie für Magento-Shops.
Migration-Audit
Risikoanalyse, Größenabschätzung und Tool-Auswahl für Ihre Schema-Änderung
Zero-Downtime
Expand/Contract-Pattern, gh-ost-Setup und paralleles App-Deployment koordinieren
Magento Schema
db_schema.xml, setup:upgrade und großskalige Datenmigrationen für Magento 2
Zusammenfassung
Eine Datenbank-Migration auf einem Produktionssystem ist immer riskant — aber beherrschbar, wenn die richtige Vorbereitung stattfindet. Die Pre-Migration-Checkliste (Backup, Replikations-Lag, Disk Space) ist nicht verhandelbar. Für große Tabellen sind gh-ost (für replizierte Setups, wenig Write-Overhead) oder pt-osc (einfacher für kleinere Tabellen) die empfohlenen Werkzeuge gegenüber nativem ALTER TABLE. Das Expand/Contract-Muster stellt Zero-Downtime sicher. Magento's db_schema.xml bietet einen deklarativen, wartbaren Weg für Schema-Verwaltung. Migrationen müssen auf Produktionsgröße getestet werden, bevor sie live gehen.
Datenbank-Migration — Das Wichtigste auf einen Blick
Pre-Migration
Backup (mysqldump --single-transaction), Replikations-Lag prüfen (SHOW REPLICA STATUS), Disk Space sicherstellen (2x Tabellengröße).
Tool-Wahl
gh-ost: Binärlog-basiert, kein Trigger-Overhead, pausierbar — bevorzugt für große Tabellen und Replikationssetups. pt-osc: Trigger-basiert, simpler für kleinere Tabellen.
Expand/Contract
1. Nullable Spalte hinzufügen. 2. App dual-write deployen. 3. Backfill. 4. NOT NULL hinzufügen. 5. Alte Spalte entfernen. Kein Rollback-Risiko.
Magento
db_schema.xml statt Install/Upgrade-Scripts. bin/magento setup:upgrade --dry-run vor dem Einsatz. Für große Tabellen gh-ost statt nativen ALTER TABLE verwenden.
FAQ: Database Migrations
1 Was ist eine Datenbank-Migration?
2 Warum ist ALTER TABLE in der Produktion riskant?
ALTER TABLE-Operationen halten eine exklusive Sperre, während MySQL die Tabelle neu aufbaut. Das kann Stunden dauern und den Schreibzugriff für alle Anwendungen blockieren.3 Was ist gh-ost?
4 Was ist pt-online-schema-change?
5 Was ist das Expand/Contract-Pattern?
6 Wie prüfe ich den Replikations-Lag?
SHOW REPLICA STATUS\G. Feld Seconds_Behind_Source sollte vor der Migration nahe 0 sein.7 Wie viel Disk Space brauche ich?
8 Wie nutzt Magento db_schema.xml?
bin/magento setup:upgrade berechnet das Delta. Mit --dry-run vorab prüfen.9 Forward-Only vs. Rollback-Migrations?
10 Was überwache ich während der Migration?
INNODB_LOCK_WAITS), Replikations-Lag (SHOW REPLICA STATUS), I/O-Auslastung und Buffer Pool Dirty Pages.