Datenbank-Migrationen sind bei Server-Wechseln, Upgrades oder Systemumstellungen unvermeidlich. Die richtige Strategie minimiert Ausfallzeiten und Datenverlust.

Migration planen

Vorüberlegungen

1. Quell- und Zielsystem identifizieren
2. Datenbankgröße ermitteln
3. Ausfallzeit-Fenster planen
4. Backup erstellen
5. Testmigration durchführen
6. Rollback-Plan vorbereiten

Checkliste

| Schritt | Erledigt | |---------|----------| | Backup der Quelldatenbank | ☐ | | Zieldatenbank vorbereitet | ☐ | | Anwendung informiert | ☐ | | Testmigration erfolgreich | ☐ | | Rollback-Plan dokumentiert | ☐ |

MySQL zu MySQL

Einfache Migration (mysqldump)

# Export von Quelldatenbank
mysqldump -h source-server -u root -p --all-databases \
    --single-transaction \
    --routines \
    --triggers \
    --events > all_databases.sql

# Import auf Zieldatenbank
mysql -h target-server -u root -p < all_databases.sql

Einzelne Datenbank

# Export
mysqldump -h source -u root -p mydb > mydb.sql

# Import
mysql -h target -u root -p mydb < mydb.sql

Mit Komprimierung

# Export komprimiert
mysqldump -u root -p mydb | gzip > mydb.sql.gz

# Import komprimiert
gunzip < mydb.sql.gz | mysql -u root -p mydb

Über SSH-Tunnel

# Direkte Pipe über SSH
mysqldump -u root -p mydb | ssh user@target "mysql -u root -p mydb"

# Mit Komprimierung
mysqldump -u root -p mydb | gzip | ssh user@target "gunzip | mysql -u root -p mydb"

Große Datenbanken

# Mit Progress-Anzeige
apt install pv

mysqldump -u root -p mydb | pv | gzip > mydb.sql.gz

# Parallel mit mydumper
apt install mydumper

mydumper -u root -p password -B mydb -o /backup/mydb
myloader -u root -p password -B mydb -d /backup/mydb

MySQL zu MariaDB

Kompatibilität

MySQL 5.7 → MariaDB 10.2+
MySQL 8.0 → MariaDB 10.3+ (mit Einschränkungen)

Inkompatibilitäten:
- JSON-Datentyp (MariaDB: LONGTEXT)
- Window Functions (unterschiedliche Syntax)
- CTEs (teilweise)
- System-Tabellen (mysql.*)

In-Place-Upgrade (gleicher Server)

# MySQL stoppen
systemctl stop mysql

# MySQL deinstallieren (Daten bleiben erhalten)
apt remove mysql-server mysql-client

# MariaDB Repository hinzufügen
curl -LsS https://r.mariadb.com/downloads/mariadb_repo_setup | bash

# MariaDB installieren
apt install mariadb-server mariadb-client

# Upgrade durchführen
mysql_upgrade -u root -p

# Service starten
systemctl start mariadb

Dump-basierte Migration

# Von MySQL exportieren
mysqldump -u root -p --all-databases \
    --routines \
    --triggers \
    --single-transaction > mysql_dump.sql

# Inkompatible Syntax anpassen (optional)
sed -i 's/utf8mb4_0900_ai_ci/utf8mb4_unicode_ci/g' mysql_dump.sql

# In MariaDB importieren
mysql -u root -p < mysql_dump.sql

Authentifizierung anpassen

-- MySQL 8.0 verwendet caching_sha2_password
-- MariaDB verwendet mysql_native_password

-- Benutzer nach Migration aktualisieren
ALTER USER 'user'@'host' IDENTIFIED WITH mysql_native_password BY 'password';

MySQL zu PostgreSQL

Unterschiede beachten

| MySQL | PostgreSQL | |-------|------------| | AUTO_INCREMENT | SERIAL | | TINYINT(1) | BOOLEAN | | DATETIME | TIMESTAMP | | DOUBLE | DOUBLE PRECISION | | TEXT | TEXT | | ENUM | CREATE TYPE | | Backticks ` | Anführungszeichen " |

Mit pgloader

# Installation
apt install pgloader

# Migrations-Konfiguration
cat > mysql2pg.load << 'EOF'
LOAD DATABASE
    FROM mysql://user:password@localhost/mydb
    INTO postgresql://user:password@localhost/mydb

WITH include drop, create tables, create indexes, reset sequences

SET maintenance_work_mem to '512MB',
    work_mem to '48MB'

CAST type datetime to timestamp using zero-dates-to-null,
     type tinyint to boolean using tinyint-to-boolean;
EOF

# Migration ausführen
pgloader mysql2pg.load

Manuelle Migration

# 1. Schema exportieren
mysqldump -u root -p --no-data mydb > schema.sql

# 2. Schema konvertieren (manuell oder mit Tool)
# Anpassungen:
# - AUTO_INCREMENT → SERIAL
# - Engine-Definitionen entfernen
# - Backticks → Anführungszeichen

# 3. In PostgreSQL importieren
psql -U postgres -d mydb -f schema_converted.sql

# 4. Daten als CSV exportieren
mysql -u root -p -N -e "SELECT * FROM users" mydb > users.csv

# 5. Daten in PostgreSQL importieren
psql -U postgres -d mydb -c "\COPY users FROM 'users.csv' CSV"

Schema-Konvertierung

-- MySQL
CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    active TINYINT(1) DEFAULT 1,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB;

-- PostgreSQL
CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    active BOOLEAN DEFAULT TRUE,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

PostgreSQL zu MySQL

Mit pgloader (umgekehrt)

# pgloader unterstützt auch PG → MySQL
cat > pg2mysql.load << 'EOF'
LOAD DATABASE
    FROM postgresql://user:password@localhost/mydb
    INTO mysql://user:password@localhost/mydb

WITH include drop, create tables

CAST type boolean to tinyint using boolean-to-tinyint;
EOF

pgloader pg2mysql.load

Manuelle Migration

# Schema exportieren
pg_dump -U postgres -s mydb > schema.sql

# Daten als CSV
psql -U postgres -d mydb -c "\COPY users TO 'users.csv' CSV HEADER"

# In MySQL importieren
mysql -u root -p mydb -e "LOAD DATA INFILE 'users.csv' INTO TABLE users FIELDS TERMINATED BY ',' ENCLOSED BY '\"' LINES TERMINATED BY '\n' IGNORE 1 ROWS"

Online-Migration (Minimale Ausfallzeit)

Mit Replikation

# 1. Slave auf Zielserver einrichten
# 2. Replikation laufen lassen
# 3. Anwendung stoppen
# 4. Replikation abschließen
# 5. Anwendung auf neuen Server umstellen

Mit gh-ost (Schema-Änderungen)

# Installation
wget https://github.com/github/gh-ost/releases/download/v1.1.5/gh-ost-binary-linux-amd64.tar.gz
tar xzf gh-ost-binary-linux-amd64.tar.gz

# Online Schema-Migration
gh-ost \
    --host=localhost \
    --database=mydb \
    --table=users \
    --user=root \
    --password=secret \
    --alter="ADD COLUMN email VARCHAR(255)" \
    --execute

Mit pt-online-schema-change

# Installation
apt install percona-toolkit

# Online-Migration
pt-online-schema-change \
    --alter "ADD COLUMN email VARCHAR(255)" \
    D=mydb,t=users \
    --execute

AWS DMS (Database Migration Service)

Konzept

Source DB → DMS Replication Instance → Target DB

Unterstützt:
- MySQL → Aurora/RDS
- Oracle → PostgreSQL
- On-Premise → Cloud

Konfiguration

{
  "rules": [
    {
      "rule-type": "selection",
      "rule-id": "1",
      "rule-name": "migrate-all",
      "object-locator": {
        "schema-name": "mydb",
        "table-name": "%"
      },
      "rule-action": "include"
    }
  ]
}

Datenvalidierung

Zeilenanzahl prüfen

# MySQL
mysql -u root -p -N -e "SELECT COUNT(*) FROM users" mydb

# PostgreSQL
psql -U postgres -t -c "SELECT COUNT(*) FROM users" mydb

Checksummen vergleichen

# pt-table-checksum
pt-table-checksum --databases=mydb h=source,u=root,p=secret

# Manuell
mysql -N -e "SELECT MD5(GROUP_CONCAT(CONCAT_WS(',',*) ORDER BY id)) FROM users" mydb

Datenintegrität

-- Primary Keys prüfen
SELECT COUNT(*) FROM users;
SELECT COUNT(DISTINCT id) FROM users;

-- NULL-Werte
SELECT COUNT(*) FROM users WHERE email IS NULL;

-- Fremdschlüssel
SELECT u.id FROM users u
LEFT JOIN orders o ON u.id = o.user_id
WHERE o.id IS NULL;

Rollback-Plan

Backup-Strategie

# Vor Migration: Vollständiges Backup
mysqldump -u root -p --all-databases > pre_migration_backup.sql

# Zeitstempel
mysqldump -u root -p mydb > mydb_$(date +%Y%m%d_%H%M%S).sql

Schneller Rollback

# Anwendung auf alten Server zurückstellen
# DNS-TTL vorher auf niedrigen Wert setzen

# Datenänderungen seit Migration übertragen
mysqldump -u root -p --where="updated_at > '2026-01-26 10:00:00'" mydb > changes.sql

Skript-Beispiel

Automatisierte Migration

#!/bin/bash
# migrate-db.sh

set -e

SOURCE_HOST="source.example.com"
TARGET_HOST="target.example.com"
DB_USER="root"
DB_PASS="password"
DATABASE="mydb"

# Backup erstellen
echo "Creating backup..."
mysqldump -h $SOURCE_HOST -u $DB_USER -p$DB_PASS \
    --single-transaction \
    --routines \
    --triggers \
    $DATABASE > /tmp/${DATABASE}_backup.sql

# Datenbank auf Ziel erstellen
echo "Creating target database..."
mysql -h $TARGET_HOST -u $DB_USER -p$DB_PASS \
    -e "CREATE DATABASE IF NOT EXISTS $DATABASE"

# Daten importieren
echo "Importing data..."
mysql -h $TARGET_HOST -u $DB_USER -p$DB_PASS $DATABASE < /tmp/${DATABASE}_backup.sql

# Validierung
echo "Validating..."
SOURCE_COUNT=$(mysql -h $SOURCE_HOST -u $DB_USER -p$DB_PASS -N \
    -e "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='$DATABASE'")
TARGET_COUNT=$(mysql -h $TARGET_HOST -u $DB_USER -p$DB_PASS -N \
    -e "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='$DATABASE'")

if [ "$SOURCE_COUNT" -eq "$TARGET_COUNT" ]; then
    echo "Migration successful! Tables: $TARGET_COUNT"
else
    echo "ERROR: Table count mismatch ($SOURCE_COUNT vs $TARGET_COUNT)"
    exit 1
fi

# Cleanup
rm /tmp/${DATABASE}_backup.sql

echo "Done!"

Zusammenfassung

| Migration | Tool | |-----------|------| | MySQL → MySQL | mysqldump | | MySQL → MariaDB | mysqldump + mysql_upgrade | | MySQL → PostgreSQL | pgloader | | PostgreSQL → MySQL | pgloader / manuell |

| Strategie | Ausfallzeit | |-----------|-------------| | Dump/Restore | Minuten bis Stunden | | Replikation | Sekunden | | Online-Tools | Minimal |

| Validierung | Methode | |-------------|---------| | Zeilenanzahl | COUNT(*) vergleichen | | Checksumme | MD5/SHA vergleichen | | Stichproben | SELECT WHERE vergleichen |

Fazit

Datenbank-Migrationen erfordern sorgfältige Planung und Tests. Für MySQL zu MariaDB sind In-Place-Upgrades oft möglich. Bei Wechsel zu PostgreSQL ist pgloader das beste Tool. Online-Migrationstools wie gh-ost minimieren Ausfallzeiten bei großen Datenbanken. Ein Rollback-Plan ist unverzichtbar. Validierung nach der Migration stellt Datenintegrität sicher.