Datenbankadministration für Sysadmins

Speicherwachstum und Routinewartung: Aufblähung, Aufräumen und der Preis des Platzes

200 Millionen Zeilen gelöscht, Vorgang fehlerfrei — und das Volume ist genauso voll wie vorher. Das ist keine Störung, sondern die dokumentierte Arbeitsweise: Alte Zeilenversionen dürfen nicht verschwinden, solange jemand sie noch sehen könnte. Dieses Modul trennt Aufblähung von echtem Wachstum, zeigt warum die Maßnahme gegen volle Platten selbst zusätzlichen Platz braucht — und behandelt die Uhr, die im Hintergrund läuft und deren Ablauf die Dokumentation als katastrophalen Datenverlust bezeichnet.

Lehrtext · 11 Abschnitte · zuletzt geprüft: 2026-09-12

Warum Löschen keinen Platz freigibt

Ein Ticket, das jeder Datenbankbetrieb kennt: Es wurden 200 Millionen alte Zeilen gelöscht, der Vorgang lief erfolgreich durch — und das Volume ist genauso voll wie vorher. Das ist kein Fehler, sondern die dokumentierte Arbeitsweise.

Aus der DokumentationIn PostgreSQL entfernt ein UPDATE oder ein DELETE einer Zeile die alte Version der Zeile nicht sofort. Dieser Ansatz ist nötig, um die Vorteile der Mehrversionen-Nebenläufigkeitssteuerung zu erhalten: Die Zeilenversion darf nicht gelöscht werden, solange sie für andere Transaktionen möglicherweise noch sichtbar ist.

Das ist dieselbe Mechanik, die im Modul über Transaktionen die Isolationsstufen trägt: Wenn eine laufende Abfrage einen Schnappschuss von vorhin sieht, muss dieser Schnappschuss irgendwo stehen. Er steht in den alten Zeilenversionen. Sie wegzuwerfen, solange jemand sie noch sehen könnte, würde die Garantie brechen.

Tote ZeilenversionEine überholte oder gelöschte Zeilenversion, für die sich keine laufende Transaktion mehr interessiert. Sie belegt Platz, bis eine Aufräumung ihn zur Wiederverwendung freigibt.

AufblähungDer Anteil einer Tabelle, der aus toten Zeilenversionen besteht. Er wächst mit der Änderungsrate und schrumpft nur durch Aufräumen.

Bei SQL Server ist die Mechanik anders, das Ergebnis vergleichbar: Auch dort gibt eine gelöschte Zeile ihren Platz nicht an das Betriebssystem zurück, sondern hinterlässt freien Raum innerhalb der Datendatei, der für neue Zeilen wiederverwendet wird.

Was das Aufräumen tut — und was nicht

Der Befehl dafür heißt in PostgreSQL VACUUM, und seine wichtigste Eigenschaft ist eine Einschränkung, die regelmäßig übersehen wird.

Wörtlich aus der DokumentationDie Standardform von VACUUM entfernt tote Zeilenversionen in Tabellen und Indizes und markiert den Platz als für künftige Wiederverwendung verfügbar. Sie gibt den Platz jedoch nicht an das Betriebssystem zurück — außer in dem Sonderfall, dass eine oder mehrere Seiten am Ende der Tabelle vollständig frei werden und sich eine exklusive Tabellensperre leicht erlangen lässt.

Nach einem erfolgreichen Aufräumen ist die Tabelle also genauso groß wie vorher — aber innen hohl. Der nächste Schwung neuer Zeilen passt hinein, ohne dass die Datei wächst. Genau das ist der Zweck.

Die Dokumentation formuliert das Ziel ausdrücklich anders, als die meisten es erwarten: Es geht nicht darum, Tabellen auf ihrer Mindestgröße zu halten, sondern einen stationären Zustand des Platzverbrauchs zu erreichen — jede Tabelle belegt ihre Mindestgröße plus so viel, wie zwischen zwei Aufräumläufen verbraucht wird.

Die gute Nachricht dabeiDie Standardform läuft parallel zum Produktionsbetrieb. SELECT, INSERT, UPDATE und DELETE funktionieren laut Dokumentation normal weiter; lediglich die Definition der Tabelle lässt sich währenddessen nicht ändern. Der Preis ist E/A-Last, die andere Sitzungen spüren können — dafür gibt es eigene Drosselungsparameter.

Der Ausweg, der mehr Platz braucht als vorhanden ist

Wenn die Aufblähung schon groß ist, reicht die Standardform nicht mehr, um die Datei zu verkleinern. Dafür gibt es VACUUM FULL — und der hat zwei Eigenschaften, die ihn im Ernstfall oft ausschließen.

Sperre
Verlangt laut Dokumentation eine ACCESS EXCLUSIVE-Sperre auf der Tabelle und kann deshalb nicht parallel zu anderer Nutzung laufen. Die Tabelle ist währenddessen vollständig unerreichbar.
Platzbedarf
Schreibt eine vollständig neue Fassung der Tabellendatei ohne toten Raum. Dafür braucht er zusätzlichen Plattenplatz etwa in der Größe der Tabelle, bis der Vorgang abgeschlossen ist.
Dauer
Läuft laut Dokumentation deutlich langsamer als die Standardform.
Die Ironie, die im Ernstfall zuschlägtGerufen wird VACUUM FULL fast immer, weil die Platte voll ist. Genau dann steht der zusätzliche Platz in Größe der Tabelle nicht zur Verfügung. Das gilt gleichermaßen für die verwandten Wege über CLUSTER und die tabellenneuschreibenden Formen von ALTER TABLE: Alle verlangen dieselbe Sperre, und alle brauchen vorübergehend den doppelten Platz, weil die alten Kopien von Tabelle und Indizes erst freigegeben werden können, wenn die neuen fertig sind.

Die Dokumentation zieht daraus eine klare Empfehlung: Administratoren sollten anstreben, die Standardform zu verwenden und VACUUM FULL zu vermeiden. Mäßig häufige Standardläufe sind der bessere Weg als seltene vollständige — und eine Tabelle auf Mindestgröße zu schrumpfen bringt ohnehin wenig, wenn sie gleich wieder wächst.

Autovacuum: was er tut und was er nie tut

Beide Systeme räumen im Hintergrund selbsttätig auf. In PostgreSQL heißt der Vorgang Autovacuum-Daemon, und er hat eine Eigenschaft, die man kennen muss, bevor man ihm ein Problem zuschreibt.

Die Grenze, die er nie überschreitetDer Daemon arbeitet mit der Standardform und wird laut Dokumentation niemals ein VACUUM FULL ausführen. Wer darauf wartet, dass die Datei durch ihn kleiner wird, wartet vergeblich — nicht weil er nicht funktioniert, sondern weil das nicht seine Aufgabe ist.

Sein Vorteil gegenüber einem festen Zeitplan liegt in der Dynamik. Die Dokumentation benennt die Schwäche des Zeitplans genau: Hat eine Tabelle einen unerwarteten Ausschlag an Änderungsaktivität, kann sie so stark aufblähen, dass ein VACUUM FULL wirklich nötig wird. Der Daemon plant dagegen anhand der tatsächlichen Aktivität. Ihn vollständig abzuschalten nennt die Dokumentation unklug, sofern die Last nicht außergewöhnlich vorhersagbar ist.

Er übernimmt dabei eine zweite Aufgabe, die im Modul über Ausführungspläne schon aufgetaucht ist: Er stößt auch ANALYZE an, sobald sich der Inhalt einer Tabelle hinreichend geändert hat. Die Dokumentation nennt die Grenze dieses Automatismus gleich mit — er plant ausschließlich anhand der Zahl eingefügter oder geänderter Zeilen und hat keine Kenntnis davon, ob daraus überhaupt eine bedeutsame statistische Änderung folgt.

Zwei Lücken, die man kennen mussDer Daemon fasst laut Dokumentation partitionierte Tabellen nicht an: Änderungen an Untertabellen lösen keine automatische Analyse der Elterntabelle aus. Ebenso wenig behandelt er Fremdtabellen. Wo Abfragen Statistiken auf diesen Ebenen brauchen, muss ein eigener Zeitplan sie erzeugen — sonst plant der Planer auf leeren Annahmen, und niemand sieht eine Fehlermeldung.

Aufräumen macht auch Abfragen schneller

Die Wirkung des Aufräumens auf den Plattenplatz ist die bekannte. Es gibt eine zweite, die weniger bekannt ist und unmittelbar auf die Abfrageleistung durchschlägt.

Beim Aufräumen wird laut Dokumentation je Tabelle eine Sichtbarkeitskarte gepflegt. Sie vermerkt, welche Seiten ausschließlich Zeilen enthalten, die für alle laufenden — und alle künftigen — Transaktionen sichtbar sind, bis die Seite wieder geändert wird. Das hat zwei Zwecke.

  • Der nächste Aufräumlauf wird kürzer. Er kann solche Seiten überspringen, weil es dort nichts zu tun gibt. Aufräumen macht das nächste Aufräumen billiger — und umgekehrt wird ein lange vernachlässigter Lauf überproportional teuer.
  • Manche Abfragen kommen ohne die Tabelle aus. Indizes tragen keine Sichtbarkeitsinformation, weshalb ein gewöhnlicher Indexzugriff zu jedem Treffer zusätzlich die Tabellenzeile holen muss, um zu prüfen, ob sie für die aktuelle Transaktion überhaupt sichtbar ist. Steht in der Sichtbarkeitskarte, dass auf einer Seite alles sichtbar ist, entfällt dieser Griff — die Abfrage wird allein aus dem Index beantwortet.
Warum das gerade bei großen Tabellen zähltDie Karte ist laut Dokumentation erheblich kleiner als die Tabelle selbst und lässt sich deshalb auch dann im Zwischenspeicher halten, wenn die Tabelle es längst nicht mehr wird. Der Nutzen ist damit dort am größten, wo die Datenmenge am größten ist. Umgekehrt heißt das: Eine große, stark geänderte Tabelle, auf der das Aufräumen hinterherhängt, verliert diese Abkürzung — und die Abfragen darauf werden langsamer, ohne dass sich am Index oder an der Abfrage irgendetwas geändert hätte.

Damit schließt sich der Kreis zum Modul über Ausführungspläne: Wer dort eine plötzlich langsamere Abfrage untersucht und in Plan und Index nichts findet, sollte prüfen, wann die Tabelle zuletzt aufgeräumt wurde. Die Ursache liegt dann nicht im Zugriffsweg, sondern in der Wartung.

Die Uhr, die niemand sieht

Es gibt einen Grund fürs Aufräumen, der nichts mit Plattenplatz zu tun hat und weit schwerer wiegt. Er ist der Grund, warum Aufräumen auch auf einer Tabelle nötig ist, die nur gelesen wird.

Die Sichtbarkeitsregeln beruhen auf dem Vergleich von Transaktionskennungen: Eine Zeilenversion mit einer höheren Einfüge-Kennung als die der aktuellen Transaktion liegt „in der Zukunft“ und soll nicht sichtbar sein. Diese Kennungen sind aber laut Dokumentation 32 Bit groß. Ein Cluster, der lange genug läuft — mehr als vier Milliarden Transaktionen — würde einen Überlauf erleiden: Der Zähler springt auf null, und plötzlich erscheinen Transaktionen, die in der Vergangenheit lagen, als in der Zukunft liegend.

Was das bedeutetDie Dokumentation nennt es beim Namen: katastrophaler Datenverlust. Und sie fügt die bittere Präzisierung hinzu — die Daten sind zwar noch da, aber das ist ein schwacher Trost, wenn man nicht mehr an sie herankommt.

Verhindert wird das durch das Einfrieren: Das Aufräumen markiert Zeilen als eingefroren, was bedeutet, dass sie von einer Transaktion eingefügt wurden, die weit genug in der Vergangenheit bestätigt hat. Eingefrorene Zeilenversionen gelten für alle normalen Transaktionen als „in der Vergangenheit“, unabhängig vom Überlauf — und bleiben damit gültig, solange sie existieren.

Die daraus folgende PflichtDeshalb ist es laut Dokumentation notwendig, jede Tabelle in jeder Datenbank mindestens einmal alle zwei Milliarden Transaktionen aufzuräumen. Das ist die eigentliche Begründung dafür, dass ein abgeschalteter oder chronisch ausgebremster Autovacuum kein Kapazitätsthema ist, sondern ein Verfügbarkeitsrisiko mit Ankündigungsfrist. Und es ist der Grund, warum „die Datenbank wird doch gar nicht mehr beschrieben“ keine Entwarnung ist.

SQL Server: Verkleinern ist keine Wartung

Auf der SQL-Server-Seite heißt die Operation, die Platz an das Betriebssystem zurückgibt, Verkleinern. Sie ist der direkte Gegenpart zu VACUUM FULL — und die Dokumentation ist in ihrer Bewertung ungewöhnlich deutlich.

Technisch arbeitet sie so: Datenseiten werden vom Ende der Datei in unbelegten Raum weiter vorne verschoben. Entsteht am Ende genügend freier Platz, können die dortigen Seiten freigegeben und an das Dateisystem zurückgegeben werden.

Die Warnung aus der DokumentationDaten, die beim Verkleinern verschoben werden, können an jede verfügbare Stelle in der Datei geraten. Das verursacht Indexfragmentierung und kann Abfragen verlangsamen, die einen Bereich des Index durchsuchen. Um die Fragmentierung zu beseitigen, sollte man erwägen, die Indizes auf der Datei danach neu aufzubauen — was wiederum Zeit, Last und Protokollaufkommen kostet.
Und der Satz, der den Wartungsplan korrigiertVerkleinerungsvorgänge sollten nicht als regelmäßige Wartungsmaßnahme betrachtet werden. Daten- und Protokolldateien, die durch regelmäßigen, wiederkehrenden Geschäftsbetrieb wachsen, brauchen laut Dokumentation keine Verkleinerung.

Dazu kommen zwei Grenzen, die überraschen. Eine Datenbank lässt sich nicht unter ihre Mindestgröße verkleinern — das ist die bei der Erstellung angegebene oder die zuletzt ausdrücklich gesetzte Größe. Eine Datenbank, die mit 10 MB erzeugt wurde und auf 100 MB gewachsen ist, lässt sich auf 10 MB verkleinern, selbst wenn alle Daten gelöscht wurden, aber nicht darunter. Und: Während eine Sicherung läuft, lässt sich nicht verkleinern — und umgekehrt.

Abkürzungen mit Preis

Es gibt zwei Wege, die Aufräumarbeit gar nicht erst entstehen zu lassen. Beide sind richtig, und beide haben einen benannten Nachteil.

TRUNCATE statt DELETE
Wird der gesamte Inhalt einer Tabelle regelmäßig geleert, entfernt TRUNCATE ihn laut Dokumentation sofort, ohne dass anschließend aufgeräumt werden müsste, um den Platz zurückzugewinnen. Nachteil: Die strengen Nebenläufigkeits-Semantiken werden dabei verletzt.
Partitionieren statt Löschen
Alte Daten liegen in einer eigenen Partition, die als Ganzes entfernt wird. Nachteil: Der Entwurf muss von Anfang an passen, und die Statistikpflege der Elterntabelle fällt aus der Automatik heraus.
Warum `TRUNCATE` kein Ersatz für `DELETE` istEs leert die Tabelle ganz. Sobald eine Bedingung im Spiel ist — „alles älter als zwei Jahre“ — ist es nicht anwendbar. Und weil es die üblichen Sichtbarkeitsregeln nicht einhält, gehört es nicht in einen Ablauf, in dem parallel jemand aus derselben Tabelle liest.

Beiden gemeinsam ist der eigentliche Lehrsatz dieses Moduls: Platz zurückzugeben ist in beiden Systemen teuer und störend. Der billige Weg besteht darin, ihn gar nicht erst in großer Menge entstehen zu lassen — durch häufiges, leichtes Aufräumen statt seltener, schwerer Eingriffe.

Das Wartungsfenster ordnen

Ein nächtliches Fenster enthält meist mehrere Arbeiten, und ihre Reihenfolge ist nicht beliebig — jede erzeugt Voraussetzungen für die nächste oder macht deren Ergebnis zunichte.

Vier Arbeiten, eine Reihenfolge

Szenario

Im Fenster stehen an: eine Vollsicherung, ein Aufräumlauf, das Auffrischen der Planerstatistiken und ein Neuaufbau stark fragmentierter Indizes.

Anforderungen

  • Begrenztes Fenster
  • Die Datenbank ist währenddessen nicht in Nutzung
  • Alle vier Arbeiten sollen wirksam sein, nicht nur ausgeführt

Schritte

  1. Aufräumen zuerst: Es entfernt tote Zeilenversionen und ist die Voraussetzung dafür, dass die folgenden Schritte nicht auf Ballast arbeiten.
  2. Indexpflege danach: Sie schreibt Indexstrukturen neu. Vorher aufzuräumen verhindert, dass tote Einträge mit übernommen werden.
  3. Statistiken danach: Sie sollen den Zustand nach allen Strukturänderungen abbilden. Frischt man sie vorher auf, beschreiben sie einen Stand, den es am Morgen nicht mehr gibt.
  4. Sicherung zuletzt: Sie soll den fertigen, aufgeräumten Stand einfangen. Eine Sicherung vor der Wartung sichert den Zustand, den man gerade loswerden wollte — bei SQL Server kollidiert sie zudem mit einer Verkleinerung, weil beides nicht gleichzeitig laufen darf.

Merksatz: Die Reihenfolge folgt der Abhängigkeit, nicht der Gewohnheit: Was Zustand verändert, kommt vor dem, was Zustand beschreibt oder konserviert.

Der Preis, den ein Fenster immer hatAlle vier Arbeiten erzeugen erhebliche E/A-Last und — bei SQL Server im Modell FULL — erhebliches Protokollaufkommen. Ein Indexneuaufbau kann die Protokolldatei stärker wachsen lassen als ein ganzer Geschäftstag. Wer das Fenster plant, plant deshalb auch den Platz, den die Wartung selbst verbraucht.

Beobachten statt reagieren

Wachstum ist der eine Fall, in dem sich ein Vorfall zuverlässig vorher ankündigt — vorausgesetzt, jemand sieht hin. Drei Größen reichen dafür weitgehend aus.

  • Der Anteil toter Zeilenversionen je Tabelle. Er zeigt, ob das Aufräumen hinterherkommt. Steigt er über Wochen, ist die Ursache die Aufräumrate, nicht die Datenmenge.
  • Der Zeitpunkt des letzten Aufräumens und Analysierens je Tabelle. Beide Systeme führen ihn mit. Eine große Tabelle, die seit Monaten nicht angefasst wurde, ist der Kandidat für beide Probleme dieses Moduls — Aufblähung und die Uhr der Transaktionskennungen.
  • Der freie Platz im Volume gegen den Zuwachs je Woche. Erst diese beiden zusammen ergeben eine Vorwarnzeit. Ein Füllstand allein ergibt sie nicht.
Was man dafür einschalten solltelog_autovacuum_min_duration protokolliert Aufräumvorgänge ab einer angegebenen Dauer; die Voreinstellung liegt bei zehn Minuten. Wichtiger als die Dauer ist ein Nebeneffekt, den die Dokumentation ausdrücklich nennt: Sobald der Wert nicht auf „aus“ steht, wird auch dann eine Meldung geschrieben, wenn ein Aufräumvorgang wegen einer konfliktierenden Sperre oder einer nebenläufig entfernten Relation übersprungen wurde. Genau diese übersprungenen Läufe sind die Ursache, wenn eine einzelne Tabelle jahrelang aufbläht, während alle anderen sauber bleiben.

Die Reihenfolge, die das zusammenhält

Unterscheiden: fehlt Platz, oder fällt Leistung?Prüfen, ob das Aufräumen überhaupt läuft und wann zuletztAufblähung von echtem Datenwachstum trennenLeichte, häufige Wartung vor schwerer, seltenerPlatz zurückgeben nur mit Fenster, Sperre und doppeltem Platz
Aufräumrate vor Größe

Schritt drei entscheidet über alles Weitere. Echtes Datenwachstum löst man mit Kapazität oder mit Archivierung. Aufblähung löst man mit Aufräumen — und wer sie für Wachstum hält, kauft Platten gegen ein Problem, das keine Platten braucht.

AbgrenzungWie Fragmentierung die Abfrageleistung beeinflusst und wann ein Index überhaupt hilft, steht im Modul über Indizes und Ausführungspläne. Warum alte Zeilenversionen überhaupt aufbewahrt werden müssen, steht im Modul über Transaktionen und Isolationsstufen. Wie ein vollgelaufenes Protokollverzeichnis zustande kommt und was es anrichtet, steht im Modul über Backup und Recovery.

Jetzt anwenden

Diesen Stoff gibt es als Modul mit bewerteten Entscheidungs-Checks — dieselbe Einführung, danach die Übungen.

Zum Modul →
Quellen & Aktualität6 Primärquellen · zuletzt geprüft:
  1. 01postgresql.org/docs/current/routine-vacuuming.html
  2. 02postgresql.org/docs/current/storage-file-layout.html
  3. 03postgresql.org/docs/current/monitoring-stats.html
  4. 04postgresql.org/docs/current/runtime-config-logging.html
  5. 05learn.microsoft.com/en-us/sql/relational-datab…es/shrink-a-database
  6. 06learn.microsoft.com/en-us/sql/relational-datab…ry-models-sql-server