Backup & Recovery

MSSQL und MariaDB Backup: Migration und Wiederherstellung Guide

MSSQL und MariaDB Backup: Migration und Wiederherstellung Guide

Einleitung

Die Migration von Datenbanken zwischen verschiedenen Systemen ist eine kritische Aufgabe in der IT-Administration. Microsoft SQL Server (MSSQL) und MariaDB sind zwei der am häufigsten eingesetzten Datenbankmanagementsysteme in Unternehmen. Während MSSQL vorwiegend in Windows-Umgebungen verwendet wird, hat sich MariaDB als leistungsstarke Open-Source-Alternative etabliert.

Dieses Tutorial behandelt die vollständige Sicherung, Migration und Wiederherstellung von MSSQL- und MariaDB-Datenbanken. Sie lernen, wie Sie strukturierte Backups erstellen, Daten zwischen verschiedenen Systemen migrieren und diese erfolgreich wiederherstellen. Dies ist besonders relevant bei Systemumstellungen, Disaster Recovery oder der Migration von proprietären zu Open-Source-Lösungen.

Systemvoraussetzungen

Hardware-Anforderungen

Komponente MSSQL Minimum MSSQL Empfohlen MariaDB Minimum MariaDB Empfohlen
CPU 1.4 GHz x64 4+ Kerne, 2.0+ GHz 1 GHz x64 4+ Kerne, 2.0+ GHz
RAM 2 GB 16+ GB 512 MB 8+ GB
Festplatte 6 GB 100+ GB SSD 200 MB 50+ GB SSD
Netzwerk 1 Gbit/s 10 Gbit/s 100 Mbit/s 1+ Gbit/s

Unterstützte Betriebssysteme

MSSQL Server 2022

  • Windows Server 2019/2022
  • Windows 10/11 (für Entwicklung)
  • Ubuntu 18.04/20.04/22.04 LTS
  • Red Hat Enterprise Linux 8/9
  • SUSE Linux Enterprise Server 15

MariaDB 10.11 LTS

  • Windows Server 2019/2022
  • Ubuntu 18.04/20.04/22.04 LTS
  • Debian 10/11/12
  • CentOS 7/8, Rocky Linux 8/9
  • Red Hat Enterprise Linux 7/8/9

Benötigte Netzwerk-Ports

Service Port Protokoll Firewall Beschreibung
MSSQL Server 1433 TCP Ja Standard SQL Server Port
MSSQL Browser 1434 UDP Optional Named Instances
MariaDB 3306 TCP Ja Standard MySQL/MariaDB Port
SSH 22 TCP Ja Remote Administration (Linux)
RDP 3389 TCP Ja Remote Administration (Windows)

Vorbereitung

Windows-System vorbereiten

# System aktualisieren
sconfig
# Wählen Sie Option 6 für Windows Updates

# .NET Framework installieren (falls nicht vorhanden)
# Laden Sie .NET Framework 4.8 von der Microsoft-Website herunter

# PowerShell auf neueste Version aktualisieren
winget install Microsoft.PowerShell

# SQL Server Management Studio installieren (optional)
winget install Microsoft.SQLServerManagementStudio

Linux-System vorbereiten (Ubuntu/Debian)

# System aktualisieren
sudo apt update && sudo apt upgrade -y

# Benötigte Pakete installieren
sudo apt install -y curl wget gnupg2 software-properties-common \
    apt-transport-https ca-certificates lsb-release unzip

# Tools für Backup und Migration
sudo apt install -y mysql-client-core-8.0 mssql-tools18
echo 'export PATH="$PATH:/opt/mssql-tools18/bin"' >> ~/.bashrc
source ~/.bashrc

Linux-System vorbereiten (RHEL/CentOS/Rocky)

# System aktualisieren
sudo dnf update -y

# EPEL Repository aktivieren
sudo dnf install -y epel-release

# Benötigte Pakete installieren
sudo dnf install -y curl wget gnupg2 unzip mysql

# Microsoft Repository für MSSQL Tools
sudo curl -o /etc/yum.repos.d/msprod.repo https://packages.microsoft.com/config/rhel/9/prod.repo
sudo dnf install -y mssql-tools18
⚠️ Wichtig: Stellen Sie sicher, dass ausreichend Speicherplatz für Backups verfügbar ist. Planen Sie mindestens das 2-3fache der Datenbankgröße ein.

MSSQL Server Installation und Konfiguration

MSSQL Server auf Windows installieren

# SQL Server 2022 Express herunterladen und installieren
# Besuchen Sie: https://www.microsoft.com/de-de/sql-server/sql-server-downloads

# Installation über Kommandozeile (nach Download)
.\SQLEXPR_x64_ENU.exe /Q /IACCEPTSQLSERVERLICENSETERMS /ACTION=install /FEATURES=SQLENGINE /INSTANCENAME=MSSQLSERVER /SQLSYSADMINACCOUNTS="BUILTIN\Administrators" /TCPENABLED=1

MSSQL Server auf Linux installieren

# Microsoft Repository hinzufügen (Ubuntu)
wget -qO- https://packages.microsoft.com/keys/microsoft.asc | sudo apt-key add -
sudo add-apt-repository "$(wget -qO- https://packages.microsoft.com/config/ubuntu/22.04/mssql-server-2022.list)"

# MSSQL Server installieren
sudo apt update
sudo apt install -y mssql-server

# MSSQL Server konfigurieren
sudo /opt/mssql/bin/mssql-conf setup

# Edition wählen (2 für Express, kostenlos)
# SA Passwort festlegen (mindestens 8 Zeichen, Groß-, Kleinbuchstaben, Zahlen, Sonderzeichen)

MariaDB Server Installation

MariaDB auf Windows installieren

# MariaDB MSI Installer herunterladen von https://mariadb.org/download/
# Installation über GUI oder Silent Install:
msiexec /i mariadb-10.11.x-winx64.msi /quiet SERVICENAME=MariaDB PASSWORD=IhrSicheresPasswort

MariaDB auf Linux installieren

# MariaDB Repository hinzufügen (Ubuntu)
sudo apt-key adv --fetch-keys 'https://mariadb.org/mariadb_release_signing_key.asc'
sudo add-apt-repository 'deb [arch=amd64,arm64,ppc64el,s390x] https://mirror.fritz.box/mariadb/repo/10.11/ubuntu jammy main'

# MariaDB installieren
sudo apt update
sudo apt install -y mariadb-server mariadb-client

# MariaDB sichern
sudo mysql_secure_installation

# Root-Passwort setzen
# Anonyme Benutzer entfernen
# Root-Remote-Login deaktivieren
# Test-Datenbank entfernen

Firewall-Konfiguration

Windows Firewall

# MSSQL Server Port freigeben
netsh advfirewall firewall add rule name="MSSQL Server" dir=in action=allow protocol=TCP localport=1433

# MariaDB Port freigeben (falls installiert)
netsh advfirewall firewall add rule name="MariaDB Server" dir=in action=allow protocol=TCP localport=3306

Linux Firewall (UFW – Ubuntu/Debian)

# UFW aktivieren
sudo ufw enable

# MSSQL Server Port freigeben
sudo ufw allow 1433/tcp comment "MSSQL Server"

# MariaDB Port freigeben
sudo ufw allow 3306/tcp comment "MariaDB Server"

# SSH Port sicherstellen
sudo ufw allow 22/tcp comment "SSH"

# Status prüfen
sudo ufw status verbose

Linux Firewall (firewalld – RHEL/CentOS)

# Firewalld starten und aktivieren
sudo systemctl start firewalld
sudo systemctl enable firewalld

# MSSQL Server Port freigeben
sudo firewall-cmd --permanent --add-port=1433/tcp
sudo firewall-cmd --permanent --add-port=3306/tcp

# Regeln laden
sudo firewall-cmd --reload

# Status prüfen
sudo firewall-cmd --list-all

Vollumfängliche Backup-Erstellung

MSSQL Server Backup

Vollständiges Backup erstellen

-- Testdatenbank erstellen (falls nicht vorhanden)
CREATE DATABASE TestDB;
GO

USE TestDB;
GO

-- Beispieltabelle und Daten erstellen
CREATE TABLE Employees (
    ID INT IDENTITY(1,1) PRIMARY KEY,
    FirstName NVARCHAR(50),
    LastName NVARCHAR(50),
    Email NVARCHAR(100),
    HireDate DATETIME DEFAULT GETDATE()
);

INSERT INTO Employees (FirstName, LastName, Email)
VALUES ('Max', 'Mustermann', 'max@example.com'),
       ('Anna', 'Schmidt', 'anna@example.com'),
       ('Peter', 'Meyer', 'peter@example.com');

-- Vollständiges Backup erstellen
BACKUP DATABASE TestDB 
TO DISK = 'C:\Backups\TestDB_Full.bak'
WITH FORMAT, 
     NAME = 'TestDB Full Backup',
     DESCRIPTION = 'Vollständiges Backup der TestDB';
GO

Skript für automatisierte MSSQL Backups

# PowerShell Backup-Skript für MSSQL
param(
    [Parameter(Mandatory=$true)]
    [string]$DatabaseName,
    
    [Parameter(Mandatory=$false)]
    [string]$BackupPath = "C:\Backups",
    
    [Parameter(Mandatory=$false)]
    [string]$ServerInstance = "localhost"
)

# Backup-Verzeichnis erstellen falls nicht vorhanden
if (!(Test-Path $BackupPath)) {
    New-Item -ItemType Directory -Path $BackupPath -Force
}

# Zeitstempel für Backup-Datei
$timestamp = Get-Date -Format "yyyyMMdd_HHmmss"
$backupFileName = "${DatabaseName}_Full_${timestamp}.bak"
$fullBackupPath = Join-Path $BackupPath $backupFileName

# SQL Query für Backup
$sqlQuery = @"
BACKUP DATABASE [$DatabaseName] 
TO DISK = '$fullBackupPath'
WITH FORMAT, 
     NAME = '$DatabaseName Full Backup $timestamp',
     DESCRIPTION = 'Automatisches vollständiges Backup';
"@

try {
    # Backup ausführen
    Invoke-Sqlcmd -ServerInstance $ServerInstance -Query $sqlQuery -QueryTimeout 0
    Write-Host "Backup erfolgreich erstellt: $fullBackupPath" -ForegroundColor Green
    
    # Backup-Informationen anzeigen
    $backupInfo = Get-ChildItem $fullBackupPath
    Write-Host "Backup-Größe: $([math]::Round($backupInfo.Length/1MB, 2)) MB"
    
} catch {
    Write-Error "Fehler beim Erstellen des Backups: $($_.Exception.Message)"
}

MariaDB Backup

Vollständiges MariaDB Backup mit mysqldump

#!/bin/bash
# MariaDB Backup Script

# Konfiguration
DB_USER="root"
DB_PASSWORD="IhrPasswort"
DB_HOST="localhost"
DB_NAME="testdb"
BACKUP_DIR="/backup/mariadb"
DATE=$(date +"%Y%m%d_%H%M%S")

# Backup-Verzeichnis erstellen
mkdir -p $BACKUP_DIR

# Testdatenbank und Tabelle erstellen (falls nicht vorhanden)
mysql -u$DB_USER -p$DB_PASSWORD -h$DB_HOST -e "
CREATE DATABASE IF NOT EXISTS $DB_NAME;
USE $DB_NAME;
CREATE TABLE IF NOT EXISTS employees (
    id INT AUTO_INCREMENT PRIMARY KEY,
    first_name VARCHAR(50),
    last_name VARCHAR(50),
    email VARCHAR(100),
    hire_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
INSERT IGNORE INTO employees (id, first_name, last_name, email) VALUES
(1, 'Max', 'Mustermann', 'max@example.com'),
(2, 'Anna', 'Schmidt', 'anna@example.com'),
(3, 'Peter', 'Meyer', 'peter@example.com');
"

# Vollständiges Backup erstellen
echo "Erstelle vollständiges Backup von $DB_NAME..."
mysqldump -u$DB_USER -p$DB_PASSWORD -h$DB_HOST \
    --single-transaction \
    --routines \
    --triggers \
    --events \
    --hex-blob \
    --opt \
    $DB_NAME > "$BACKUP_DIR/${DB_NAME}_full_${DATE}.sql"

# Backup komprimieren
gzip "$BACKUP_DIR/${DB_NAME}_full_${DATE}.sql"

echo "Backup erfolgreich erstellt: $BACKUP_DIR/${DB_NAME}_full_${DATE}.sql.gz"

# Backup-Größe anzeigen
ls -lh "$BACKUP_DIR/${DB_NAME}_full_${DATE}.sql.gz"

MariaDB Binäres Backup mit Mariabackup

#!/bin/bash
# Mariabackup für konsistente Hot-Backups

BACKUP_USER="backup_user"
BACKUP_PASSWORD="backup_password"
BACKUP_DIR="/backup/mariadb/hot"
DATE=$(date +"%Y%m%d_%H%M%S")
FULL_BACKUP_DIR="$BACKUP_DIR/full_$DATE"

# Backup-Benutzer erstellen (einmalig)
mysql -uroot -p -e "
CREATE USER IF NOT EXISTS '$BACKUP_USER'@'localhost' IDENTIFIED BY '$BACKUP_PASSWORD';
GRANT RELOAD, LOCK TABLES, PROCESS, REPLICATION CLIENT ON *.* TO '$BACKUP_USER'@'localhost';
GRANT SELECT ON mysql.user TO '$BACKUP_USER'@'localhost';
FLUSH PRIVILEGES;
"

# Backup-Verzeichnis erstellen
mkdir -p $FULL_BACKUP_DIR

# Vollständiges Hot-Backup erstellen
echo "Erstelle vollständiges Hot-Backup..."
mariabackup --backup \
    --target-dir=$FULL_BACKUP_DIR \
    --user=$BACKUP_USER \
    --password=$BACKUP_PASSWORD \
    --host=localhost

# Backup für Wiederherstellung vorbereiten
echo "Bereite Backup für Wiederherstellung vor..."
mariabackup --prepare --target-dir=$FULL_BACKUP_DIR

echo "Hot-Backup erfolgreich erstellt in: $FULL_BACKUP_DIR"
du -sh $FULL_BACKUP_DIR

Datenbank-Migration zwischen MSSQL und MariaDB

MSSQL zu MariaDB Migration

Schema-Export aus MSSQL

-- Schema-Informationen aus MSSQL extrahieren
USE TestDB;

-- Tabellen-Schema exportieren
SELECT 
    TABLE_NAME,
    COLUMN_NAME,
    DATA_TYPE,
    CHARACTER_MAXIMUM_LENGTH,
    IS_NULLABLE,
    COLUMN_DEFAULT
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_CATALOG = 'TestDB'
ORDER BY TABLE_NAME, ORDINAL_POSITION;

-- Indizes exportieren
SELECT 
    i.name AS IndexName,
    t.name AS TableName,
    c.name AS ColumnName,
    i.is_unique
FROM sys.indexes i
INNER JOIN sys.index_columns ic ON i.object_id = ic.object_id AND i.index_id = ic.index_id
INNER JOIN sys.columns c ON ic.object_id = c.object_id AND ic.column_id = c.column_id
INNER JOIN sys.tables t ON i.object_id = t.object_id
WHERE t.name = 'Employees';

Migration Script (Python)

#!/usr/bin/env python3
"""
MSSQL zu MariaDB Migration Script
"""

import pyodbc
import mysql.connector
import pandas as pd
import sys
from datetime import datetime

class DatabaseMigration:
    def __init__(self, mssql_conn_str, mariadb_config):
        self.mssql_conn_str = mssql_conn_str
        self.mariadb_config = mariadb_config
        
    def connect_mssql(self):
        """MSSQL Verbindung herstellen"""
        try:
            conn = pyodbc.connect(self.mssql_conn_str)
            print("✓ MSSQL Verbindung hergestellt")
            return conn
        except Exception as e:
            print(f"✗ MSSQL Verbindungsfehler: {e}")
            return None
    
    def connect_mariadb(self):
        """MariaDB Verbindung herstellen"""
        try:
            conn = mysql.connector.connect(**self.mariadb_config)
            print("✓ MariaDB Verbindung hergestellt")
            return conn
        except Exception as e:
            print(f"✗ MariaDB Verbindungsfehler: {e}")
            return None
    
    def get_mssql_tables(self, mssql_conn):
        """Tabellenliste aus MSSQL abrufen"""
        query = """
        SELECT TABLE_NAME 
        FROM INFORMATION_SCHEMA.TABLES 
        WHERE TABLE_TYPE = 'BASE TABLE'
        """
        cursor = mssql_conn.cursor()
        cursor.execute(query)
        tables = [row[0] for row in cursor.fetchall()]
        cursor.close()
        return tables
    
    def convert_datatype(self, mssql_type, length=None):
        """MSSQL Datentyp zu MariaDB konvertieren"""
        type_mapping = {
            'int': 'INT',
            'bigint': 'BIGINT',
            'smallint': 'SMALLINT',
            'tinyint': 'TINYINT',
            'bit': 'BOOLEAN',
            'decimal': 'DECIMAL',
            'numeric': 'DECIMAL',
            'money': 'DECIMAL(19,4)',
            'float': 'DOUBLE',
            'real': 'FLOAT',
            'datetime': 'DATETIME',
            'datetime2': 'DATETIME',
            'smalldatetime': 'DATETIME',
            'date': 'DATE',
            'time': 'TIME',
            'timestamp': 'TIMESTAMP',
            'char': f'CHAR({length})' if length else 'CHAR(255)',
            'varchar': f'VARCHAR({length})' if length else 'VARCHAR(255)',
            'nchar': f'CHAR({length})' if length else 'CHAR(255)',
            'nvarchar': f'VARCHAR({length})' if length else 'VARCHAR(255)',
            'text': 'TEXT',
            'ntext': 'TEXT',
            'image': 'LONGBLOB',
            'binary': f'BINARY({length})' if length else 'BINARY(255)',
            'varbinary': f'VARBINARY({length})' if length else 'VARBINARY(255)'
        }
        return type_mapping.get(mssql_type.lower(), 'TEXT')
    
    def migrate_table_schema(self, table_name, mssql_conn, mariadb_conn):
        """Tabellen-Schema migrieren"""
        # Schema aus MSSQL lesen
        schema_query = """
        SELECT 
            COLUMN_NAME,
            DATA_TYPE,
            CHARACTER_MAXIMUM_LENGTH,
            IS_NULLABLE,
            COLUMN_DEFAULT
        FROM INFORMATION_SCHEMA.COLUMNS
        WHERE TABLE_NAME = ?
        ORDER BY ORDINAL_POSITION
        """
        
        mssql_cursor = mssql_conn.cursor()
        mssql_cursor.execute(schema_query, table_name)
        columns = mssql_cursor.fetchall()
        mssql_cursor.close()
        
        # CREATE TABLE Statement für MariaDB generieren
        create_table = f"CREATE TABLE IF NOT EXISTS {table_name} (\n"
        column_definitions = []
        
        for col in columns:
            col_name, data_type, max_length, is_nullable, default_val = col
            
            mariadb_type = self.convert_datatype(data_type, max_length)
            nullable = "NULL" if is_nullable == "YES" else "NOT NULL"
            
            # Auto-Increment für IDENTITY Spalten
            if data_type.lower() == 'int' and 'IDENTITY' in str(default_val):
                mariadb_type += " AUTO_INCREMENT PRIMARY KEY"
                nullable = "NOT NULL"
            
            column_def = f"    {col_name} {mariadb_type} {nullable}"
            column_definitions.append(column_def)
        
        create_table += ",\n".join(column_definitions) + "\n);"
        
        # Tabelle in MariaDB erstellen
        mariadb_cursor = mariadb_conn.cursor()
        try:
            mariadb_cursor.execute(create_table)
            mariadb_conn.commit()
            print(f"✓ Schema für Tabelle '{table_name}' erstellt")
        except Exception as e:
            print(f"✗ Fehler beim Erstellen der Tabelle '{table_name}': {e}")
        finally:
            mariadb_cursor.close()
    
    def migrate_table_data(self, table_name, mssql_conn, mariadb_conn, batch_size=1000):
        """Tabellendaten migrieren"""
        try:
            # Daten aus MSSQL lesen
            df = pd.read_sql(f"SELECT * FROM {table_name}", mssql_conn)
            
            if df.empty:
                print(f"⚠ Tabelle '{table_name}' ist leer")
                return
            
            # Spaltennamen für INSERT vorbereiten
            columns = ', '.join(df.columns)
            placeholders = ', '.join(['%s'] * len(df.columns))
            
            mariadb_cursor = mariadb_conn.cursor()
            
            # Daten in Batches einfügen
            for i in range(0, len(df), batch_size):
                batch = df.iloc[i:i+batch_size]
                values = [tuple(row) for row in batch.values]
                
                insert_query = f"INSERT INTO {table_name} ({columns}) VALUES ({placeholders})"
                mariadb_cursor.executemany(insert_query, values)
                mariadb_conn.commit()
                
                print(f"✓ {len(values)} Zeilen in '{table_name}' migriert (Batch {i//batch_size + 1})")
            
            mariadb_cursor.close()
            print(f"✓ Alle Daten für Tabelle '{table_name}' migriert ({len(df)} Zeilen)")
            
        except Exception as e:
            print(f"✗ Fehler bei der Datenmigration für '{table_name}': {e}")

# Hauptprogramm
if __name__ == "__main__":
    # Verbindungsparameter
    mssql_conn_str = (
        "DRIVER={ODBC Driver 18 for SQL Server};"
        "SERVER=localhost;"
        "DATABASE=TestDB;"
        "Trusted_Connection=yes;"
        "TrustServerCertificate=yes;"
    )
    
    mariadb_config = {
        'host': 'localhost',
        'user': 'root',
        'password': 'IhrPasswort',
        'database': 'testdb_migrated',
        'charset': 'utf8mb4'
    }
    
    # Migration starten
    migration = DatabaseMigration(mssql_conn_str, mariadb_config)
    
    # Verbindungen herstellen
    mssql_conn = migration.connect_mssql()
    mariadb_conn = migration.connect_mariadb()
    
    if not mssql_conn or not mariadb_conn:
        sys.exit(1)
    
    try:
        # Zieldatenbank erstellen
        mariadb_cursor = mariadb_conn.cursor()
        mariadb_cursor.execute("CREATE DATABASE IF NOT EXISTS testdb_migrated")
        mariadb_cursor.execute("USE testdb_migrated")
        mariadb_cursor.close()
        
        # Tabellen abrufen und migrieren
        tables = migration.get_mssql_tables(mssql_conn)
        print(f"Gefundene Tabellen: {tables}")
        
        for table in tables:
            print(f"\n--- Migriere Tabelle: {table} ---")
            migration.migrate_table_schema(table, mssql_conn, mariadb_conn)
            migration.migrate_table_data(table, mssql_conn, mariadb_conn)
        
        print("\n✓ Migration abgeschlossen!")
        
    finally:
        mssql_conn.close()
        mariadb_conn.close()

MariaDB zu MSSQL Migration

#!/bin/bash
# MariaDB zu MSSQL Export Script

DB_USER="root"
DB_PASSWORD="IhrPasswort"
DB_NAME="testdb"
EXPORT_DIR="/tmp/migration"

mkdir -p $EXPORT_DIR

# Schema-kompatiblen Export erstellen
mysqldump -u$DB_USER -p$DB_PASSWORD \
    --compatible=mssql \
    --single-transaction \
    --no-auto-rehash \
    --skip-extended-insert \
    --skip-comments \
    $DB_NAME > "$EXPORT_DIR/${DB_NAME}_for_mssql.sql"

# Manuelle Nachbearbeitung für MSSQL-Kompatibilität
sed -i 's/AUTO_INCREMENT/IDENTITY(1,1)/g' "$EXPORT_DIR/${DB_NAME}_for_mssql.sql"
sed -i 's/ENGINE=InnoDB DEFAULT CHARSET=utf8mb4//g' "$EXPORT_DIR/${DB_NAME}_for_mssql.sql"
sed -i 's/`//g' "$EXPORT_DIR/${DB_NAME}_for_mssql.sql"

echo "Export für MSSQL vorbereitet: $EXPORT_DIR/${DB_NAME}_for_mssql.sql"

Dienste starten und konfigurieren

Windows Services

# MSSQL Server Service starten
Start-Service MSSQLSERVER
Set-Service MSSQLSERVER -StartupType Automatic

# SQL Server Browser (optional)
Start-Service SQLB