Inhaltsverzeichnis23 Abschnitte
- Warum Delta-Maintenance zählt
- OPTIMIZE: Kleine Files kompaktieren
- Basis-Nutzung
- Wann OPTIMIZE laufen lassen
- OPTIMIZE-Performance-Tipps
- VACUUM: Storage zurückgewinnen
- Basis-Nutzung
- VACUUM-Sicherheitsregeln
- VACUUM automatisieren
- Z-ORDER: Datenlayout für gefilterte Queries optimieren
- Basis-Nutzung
- Wann Z-ORDER sinnvoll ist
- Z-ORDER vs Partitionierung
- Zusammen: Ein Wartungs-Schedule
- Tabellen-Health monitoren
- Häufige Fehler vermeiden
- FAQ
- Wie oft soll ich VACUUM laufen lassen?
- Was ist der Unterschied zwischen Liquid Clustering und Z-ORDER?
- Wirkt sich Wartung auf DSGVO-Löschungen aus?
- Kann ich OPTIMIZE und VACUUM parallel laufen lassen?
- Lohnt sich Z-ORDER auf kleinen Tabellen (< 1 GB)?
- Schluss
TL;DR: Delta-Tabellen brauchen regelmäßige Wartung:
OPTIMIZEkompaktiert kleine Files,VACUUMlöscht obsolete Files (mit 7-Tage-Retention-Default),Z-ORDERclustert Daten für besseres Data-Skipping. Pro Tabelle: nach jedem Batch OPTIMIZE, wöchentlich VACUUM (Retention 168h), Z-ORDER auf High-Cardinality-Filter-Spalten.
Delta Lake ist das Rückgrat moderner Lakehouse-Architekturen auf Databricks — und wie jede Datenbank-Engine braucht es regelmäßige Wartung, um performant zu bleiben. Ohne Pflege akkumulieren Delta-Tabellen kleine Files, veraltete Snapshots und suboptimale Datenlayouts — das killt Query-Performance still und bläht Storage-Kosten auf.
In diesem Guide gehen wir die drei Kern-Wartungsoperationen durch, die jeder Databricks Data Engineer beherrschen muss:
- OPTIMIZE — kleine Files zu größeren, schneller lesbaren Parquet-Files zusammenfassen
- VACUUM — obsolete Files entfernen, die nicht mehr vom Transaction-Log referenziert werden
- Z-ORDER — verwandte Daten innerhalb von Files zusammenlegen, um gefilterte Queries drastisch zu beschleunigen
Warum Delta-Maintenance zählt
Delta Lake nutzt Copy-on-Write: jeder Write — INSERT, UPDATE, MERGE, DELETE — erzeugt neue Parquet-Files. Es überschreibt keine. Mit der Zeit führt das zu:
| Problem | Ursache | Auswirkung |
|---|---|---|
| Kleine Files | Häufige Streaming-/Inkrementell-Writes | Langsame Reads, hoher Driver-Overhead |
| Veraltete Snapshots | Time-Travel-Daten kumulieren | Storage-Waste, steigende Cloud-Rechnung |
| Schlechtes Data-Skipping | Zufällig verteilte Files | Full-Scans statt gezielter Reads |
Die Probleme verstärken sich: Eine Tabelle mit 1000 Micro-Batch-Writes pro Tag erzeugt 1000+ kleine Files. Nach einer Woche muss Sparks Query-Planner Tausende Files für selbst einfache Aggregationen öffnen.
OPTIMIZE: Kleine Files kompaktieren
OPTIMIZE schreibt kleine Parquet-Files in größere Ziel-Files um (Default: 1 GB). Der größte Hebel für bessere Read-Performance auf häufig geschriebenen Tabellen.
Basis-Nutzung
-- SQL
OPTIMIZE events;
-- With partition filter (process only recent data)
OPTIMIZE events WHERE date >= '2024-01-01';
# PySpark
from delta.tables import DeltaTable
dt = DeltaTable.forName(spark, "events")
dt.optimize().executeCompaction()
# With partition filter
dt.optimize().where("date >= '2024-01-01'").executeCompaction()
Wann OPTIMIZE laufen lassen
| Szenario | Empfohlene Frequenz |
|---|---|
| Streaming-Tabellen (Micro-Batch) | Stündlich oder nach N Commits |
| Tägliche Batch-Loads | Nach jedem Load |
| Selten geschriebene Tabellen | Wöchentlich |
| MERGE-lastige Tabellen | Nach jedem MERGE |
Pro-Tipp: Databricks unterstützt Auto Optimize (Auto-Compaction + Optimized-Writes) auf Tabellen- oder Session-Ebene. Auf Tabellen mit häufigen kleinen Writes aktivieren:
ALTER TABLE events SET TBLPROPERTIES ( 'delta.autoOptimize.optimizeWrite' = 'true', 'delta.autoOptimize.autoCompact' = 'true' );
OPTIMIZE-Performance-Tipps
- Immer nach Partition-Spalte filtern, um nicht die gesamte Tabelle zu reprozessieren
- OPTIMIZE in Off-Peak-Stunden — Compute-intensive Operation
- Via
DESCRIBE HISTORYprüfen, wann der letzte OPTIMIZE lief
DESCRIBE HISTORY events LIMIT 10;
VACUUM: Storage zurückgewinnen
VACUUM entfernt Files, die nicht mehr vom Delta-Transaction-Log referenziert werden. Essentiell für Storage-Kosten-Kontrolle, aber mit kritischem Gotcha: es löscht Files permanent, inklusive die für Time-Travel benötigten.
Basis-Nutzung
-- Default: retain 7 days of history
VACUUM events;
-- Custom retention (minimum 7 days unless safety check is disabled)
VACUUM events RETAIN 168 HOURS;
-- Dry run: see what would be deleted without actually deleting
VACUUM events DRY RUN;
# PySpark
dt = DeltaTable.forName(spark, "events")
dt.vacuum(168) # 168 hours = 7 days
VACUUM-Sicherheitsregeln
| Regel | Warum |
|---|---|
| Nie unter 7-Tage-Retention | Aktive Streaming-Jobs könnten ältere Snapshots referenzieren |
| Immer Dry-Run zuerst in Produktion | Löschung ist irreversibel |
| Mit Time-Travel-Usern abstimmen | Teams mit VERSION AS OF brauchen die Files |
| Erst auf laufende Streams prüfen | In-Progress-Streams halten Referenzen auf alte Files |
Warnung: Den 7-Tage-Retention-Check zu umgehen erfordert explizit
spark.databricks.delta.retentionDurationCheck.enabled = false. In Produktion niemals ohne komplettes Verständnis aller Downstream-Konsumenten.
VACUUM automatisieren
Empfohlener Ansatz: Scheduled Databricks Job:
# maintenance_job.py — schedule as a Databricks Workflow
from delta.tables import DeltaTable
TABLES_TO_VACUUM = [
"catalog.schema.events",
"catalog.schema.users",
"catalog.schema.transactions",
]
for table_name in TABLES_TO_VACUUM:
print(f"Vacuuming {table_name}...")
dt = DeltaTable.forName(spark, table_name)
dt.vacuum(168)
print(f" Done.")
Z-ORDER: Datenlayout für gefilterte Queries optimieren
Z-ORDER (auch Multi-Dimensional-Clustering) co-lokalisiert physisch Zeilen mit ähnlichen Werten in denselben Files. Das supercharged Delta-Lakes Data-Skipping — die Fähigkeit, ganze Files beim Scan zu überspringen, weil Min/Max-Statistiken beweisen, dass keine passenden Zeilen existieren.
Basis-Nutzung
-- Z-ORDER on a single column
OPTIMIZE events ZORDER BY (user_id);
-- Z-ORDER on multiple columns (diminishing returns after 3-4)
OPTIMIZE events ZORDER BY (country, event_type, user_id);
# PySpark
dt = DeltaTable.forName(spark, "events")
dt.optimize().executeZOrderBy("country", "event_type", "user_id")
Wann Z-ORDER sinnvoll ist
| Use-Case | Nutzen |
|---|---|
High-Cardinality-Filter-Spalten (user_id, session_id) | Massives File-Skipping |
| Häufige GROUP-BY-Spalten | Weniger Files pro Gruppe gelesen |
| JOIN-Keys auf großen Tabellen | Reduziert Shuffle-Overhead |
| Time-Series mit Non-Partition-Datums-Filtern | Files außerhalb Date-Range überspringen |
Z-ORDER vs Partitionierung
Häufiger Fehler: Z-ORDER auf einer Spalte, die eigentlich Partition sein sollte:
| Dimension | Partitionierung | Z-ORDER |
|---|---|---|
| Am besten für | Low-Cardinality (date, country, status) | High-Cardinality (user_id, session_id) |
| Mechanismus | Physische Directory-Trennung | File-Level-Statistiken + Clustering |
| Query-Nutzen | Ganze Directories übersprungen | Files innerhalb Partitionen übersprungen |
| Write-Kosten | Niedrig | Hoch (schreibt Files um) |
| Ideale Spalten-Anzahl | 1–3 | 2–4 |
Faustregel: nach
dateoderregionpartitionieren, Z-ORDER auf der High-Cardinality-Spalte, auf die am häufigsten gefiltert wird.
Zusammen: Ein Wartungs-Schedule
Produktionsreifes Wartungs-Pattern für eine typische Lakehouse-Tabelle mit täglichen Batch-Loads:
# full_maintenance.py
from delta.tables import DeltaTable
from pyspark.sql import SparkSession
spark = SparkSession.builder.getOrCreate()
def maintain_table(table_name: str, zorder_cols: list[str], vacuum_hours: int = 168):
print(f"\n=== Maintaining: {table_name} ===")
dt = DeltaTable.forName(spark, table_name)
print(" Running OPTIMIZE + Z-ORDER...")
dt.optimize().executeZOrderBy(*zorder_cols)
print(f" Running VACUUM (retain {vacuum_hours}h)...")
dt.vacuum(vacuum_hours)
print(" Done.")
maintain_table("catalog.schema.events", zorder_cols=["user_id", "event_type"])
maintain_table("catalog.schema.sessions", zorder_cols=["session_id"])
maintain_table("catalog.schema.products", zorder_cols=["product_id", "category"])
Als Databricks-Workflow nach deinem täglichen ETL einplanen — und die Query-Zeiten bleiben konsistent, auch wenn Datenvolumen wachsen.
Tabellen-Health monitoren
Vor und nach der Wartung DESCRIBE DETAIL nutzen, um den Tabellen-State zu verstehen:
DESCRIBE DETAIL catalog.schema.events;
Wichtige Metriken:
| Feld | Was es sagt |
|---|---|
numFiles | Hoch = OPTIMIZE nötig |
sizeInBytes | Gesamt-Storage-Footprint |
numPartitions | Partition-Anzahl |
Mit DESCRIBE HISTORY aktuelle Operationen auditieren:
DESCRIBE HISTORY catalog.schema.events LIMIT 20;
Häufige Fehler vermeiden
- OPTIMIZE ohne Partition-Filter auf riesigen Tabellen — verarbeitet alle historischen Daten, verbrennt Compute
- VACUUM auf Tabellen mit hoher Write-Frequenz vergessen — Storage-Kosten explodieren
- Z-ORDER auf zu vielen Spalten — Effektivität nimmt nach 3–4 Spalten ab
- VACUUM während aktiver Streaming-Jobs — kann Streams brechen, die auf alte Checkpoints referenzieren
DESCRIBE HISTORYnicht checken — du fliegst blind
FAQ
Wie oft soll ich VACUUM laufen lassen?
Wöchentlich für hochfrequent geschriebene Tabellen, monatlich für selten geschriebene. Retention 168h (7 Tage) als Default, höher nur bei aktiven Time-Travel-Konsumenten.
Was ist der Unterschied zwischen Liquid Clustering und Z-ORDER?
Liquid Clustering (DBR 13.3+) ist die moderne Variante — automatisches inkrementelles Clustering ohne OPTIMIZE-Calls. Z-ORDER ist manuell und voll umschreibend. Auf neuen Tabellen: Liquid Clustering wählen.
Wirkt sich Wartung auf DSGVO-Löschungen aus?
Ja — DSGVO-Lösch-Anfragen müssen über DELETE-Statements laufen, dann muss VACUUM darauf folgen, um die Files endgültig zu entfernen. Sonst bleibt der Datensatz via Time-Travel rekonstruierbar.
Kann ich OPTIMIZE und VACUUM parallel laufen lassen?
Nicht auf derselben Tabelle. Auf verschiedenen Tabellen: ja. In Produktion: OPTIMIZE und VACUUM seriell pro Tabelle, mehrere Tabellen parallel.
Lohnt sich Z-ORDER auf kleinen Tabellen (< 1 GB)?
Nein. Unter ~10 GB ist der Z-ORDER-Aufwand größer als der Query-Speedup. Erst sinnvoll, wenn deine Tabelle groß genug ist, dass Data-Skipping signifikant zählt.
Schluss
Delta-Table-Maintenance ist nicht glamourös, aber sie ist es, was einen Lakehouse, der bei 100 TB elegant skaliert, von einem unterscheidet, der zum Support-Albtraum wird. Die Operationen sind simpel — OPTIMIZE zum Kompaktieren, VACUUM zum Aufräumen, Z-ORDER zum Co-Lokalisieren — aber die Disziplin, sie konsistent laufen zu lassen und ihren Impact zu monitoren, macht den Unterschied.
Stand: 14. Mai 2026.
Geschrieben von
Harbinger Team
Cloud-, Data- und AI-Engineer in DACH. Schreibt seit 2018 über infrastrukturkritische Tech-Entscheidungen — keine Marketing- Folien, sondern echte Trade-offs aus Production-Workloads.
Hat dir das geholfen?
Jede Woche ein neuer Artikel über DACH-Cloud, Data und AI — direkt in dein Postfach. Kein Spam, kein Marketing-Sprech.
Kein Spam. 1-Klick-Abmeldung. Datenschutz bei Loops.so.