DDL
ALTER
SQL · MySQL · Schema Migration · Zero-Downtime
Database Migrations sicher fahren:
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.

15 Min. Lesezeit Migration · gh-ost · pt-osc MySQL 8 · Magento 2

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?
Eine kontrollierte Änderung des Datenbankschemas oder der Daten — mit Backup, Plan und Rollback-Strategie. In der Produktion bedeutet das: Änderungen ohne Downtime und mit minimalem Risiko.
2 Warum ist ALTER TABLE in der Produktion riskant?
Bestimmte 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?
GitHub's Online Schema Change Tool — verwendet das Binärlog statt Trigger. Ideal für große Tabellen, Replikationssetups und write-heavy Workloads. Kann während der Migration pausiert werden.
4 Was ist pt-online-schema-change?
Tool aus dem Percona Toolkit — trigger-basierter Online-Schema-Wechsel. Gut für kleinere bis mittlere Tabellen. Bei sehr write-heavy Tabellen ist gh-ost zu bevorzugen.
5 Was ist das Expand/Contract-Pattern?
Dreistufige Zero-Downtime-Strategie: (1) Nullable Spalte hinzufügen, (2) Dual-Write und Backfill, (3) NOT NULL setzen und alte Spalte entfernen. Jede Phase ist backward-kompatibel.
6 Wie prüfe ich den Replikations-Lag?
Auf dem Replica: SHOW REPLICA STATUS\G. Feld Seconds_Behind_Source sollte vor der Migration nahe 0 sein.
7 Wie viel Disk Space brauche ich?
Mindestens doppelt so viel freien Speicher wie die Tabelle groß ist. gh-ost und pt-osc erstellen eine vollständige Tabellenkopie mit dem neuen Schema.
8 Wie nutzt Magento db_schema.xml?
Magento 2.3+ beschreibt das gewünschte Schema deklarativ in XML. bin/magento setup:upgrade berechnet das Delta. Mit --dry-run vorab prüfen.
9 Forward-Only vs. Rollback-Migrations?
Forward-Only: Fehler werden durch neue Migrationen behoben. Rollback: jede Migration hat eine Down-Version — aber oft nicht verlustlos möglich. Expand/Contract macht explizite Rollbacks weitgehend unnötig.
10 Was überwache ich während der Migration?
Aktive Verbindungen, Lock Waits (INNODB_LOCK_WAITS), Replikations-Lag (SHOW REPLICA STATUS), I/O-Auslastung und Buffer Pool Dirty Pages.