Aufrechterhaltung der Indexgesundheit in PostgreSQL: Wann REINDEX oder VACUUM FULL wählen
Emily Parker
Product Engineer · Leapcell

Die Aufrechterhaltung einer optimalen Leistung in einer PostgreSQL-Datenbank hängt oft von der Effizienz ihrer Indizes ab. Im Laufe der Zeit können Indizes aufgrund häufiger Aktualisierungen und Löschungen aufgebläht oder fragmentiert werden, was zu langsameren Abfrageausführungen und einem erhöhten Speicherverbrauch führt. Diese Verschlechterung ist keine geringfügige Unannehmlichkeit; sie kann die Reaktionsfähigkeit der Anwendung und die allgemeine Systemgesundheit erheblich beeinträchtigen. Das Verständnis der verfügbaren Werkzeuge zur Bekämpfung dieses Problems – insbesondere REINDEX und VACUUM FULL – und zu wissen, wann und wie sie anzuwenden sind, ist für jeden Datenbankadministrator oder Entwickler von entscheidender Bedeutung. Dieser Artikel befasst sich mit diesen beiden leistungsstarken Befehlen, untersucht ihre zugrunde liegenden Mechanismen, Anwendungsfälle und praktischen Auswirkungen, um Ihre PostgreSQL-Indizes in Topform zu halten.
Die Grundlagen verstehen: Bloat, Indizes und MVCC
Bevor wir uns mit REINDEX und VACUUM FULL befassen, wollen wir kurz einige Kernkonzepte ansprechen.
Index Bloat: In PostgreSQL werden beim Aktualisieren oder Löschen von Zeilen die alten Versionen dieser Zeilen (und ihre entsprechenden Indexeinträge) nicht sofort entfernt. Stattdessen werden sie als "tote Tupel" markiert. Obwohl autovacuum diese schließlich bereinigt, kann eine hohe Änderungsrate zu einer erheblichen Ansammlung von toten Tupeln führen, wodurch Indizes größer als nötig werden. Dieser unnötige Speicherverbrauch und die Notwendigkeit, mehr Datenseiten zu lesen, stellen "Index Bloat" dar. Bloat wirkt sich direkt auf die Leistung aus, da mehr Daten von der Festplatte gelesen werden müssen und die Cache-Auslastung weniger effektiv wird.
PostgreSQL Indizes: Ein Index ist eine spezielle Nachschlagetabelle, die die Datenbank-Suchmaschine verwenden kann, um die Datenabfrage zu beschleunigen. Es ist im Wesentlichen eine sortierte Liste von Werten aus den indizierten Spalten, zusammen mit Zeigern zu den tatsächlichen Zeilen in der Tabelle. Wenn eine Abfrage eine indizierte Spalte verwendet, kann PostgreSQL die relevanten Zeilen schnell lokalisieren, ohne die gesamte Tabelle durchsuchen zu müssen.
MVCC (Multi-Version Concurrency Control): PostgreSQL implementiert MVCC, um gleichzeitige Transaktionen zu verarbeiten, ohne ganze Tabellen zu sperren. Wenn eine Zeile aktualisiert wordt, wird eine neue Version der Zeile erstellt, und die alte Version bleibt für Transaktionen sichtbar, die vor der Aktualisierung gestartet wurden. Dieser Mechanismus, obwohl hervorragend für die Nebenläufigkeit, ist die Wurzelursache für tote Tupel und folglich für Bloat.
REINDEX: Indizes inkrementell neu aufbauen
REINDEX ist ein Befehl zum Neuerstellen eines oder mehrerer vorhandener Indizes. Wenn Sie REINDEX ausführen, verwirft PostgreSQL im Wesentlichen den alten Index (oder markiert seine Einträge als ungültig) und erstellt ihn dann anhand der aktuellen, aktiven Daten in der Tabelle neu. Dieser Prozess eliminiert jeden Bloat in der alten Indexstruktur, da alle toten Tupel verworfen werden und der neue Index nur mit aktiven Zeigern aufgebaut wird.
Wie REINDEX funktioniert
Auf hoher Ebene beinhaltet REINDEX:
- Scannen der Tabelle: Sie liest die gesamte Tabelle, um alle aktiven Zeilen zu identifizieren.
- Aufbau eines neuen Indexes: Basierend auf den aktiven Zeilen wird eine völlig neue Indexstruktur erstellt.
- Ersetzen des alten Indexes: Sobald der neue Index erstellt ist, ersetzt er den alten, atomar.
Wann REINDEX verwendet werden sollte
REINDEX ist das Hauptwerkzeug zur Bekämpfung von Index Bloat. Sie sollten die Verwendung in den folgenden Szenarien in Betracht ziehen:
- Signifikanter Index Bloat: Wenn Werkzeuge wie
pg_stats_reportsoderpg_bloat_checkeinen hohen Prozentsatz an Bloat in einem Index angeben. - Leistungsverschlechterung: Wenn Abfragen, die einen bestimmten Index verwenden, spürbar langsamer werden und Sie vermuten, dass Index Bloat die Ursache ist.
- Beschädigung: In seltenen Fällen, wenn ein Index beschädigt wird, kann
REINDEXihn effektiv reparieren, indem er ihn aus den Tabellendaten neu aufbaut. - Ändern von Indexparametern: Zum Anwenden neuer Speicherparameter oder
fillfactor-Einstellungen auf einen bestehenden Index.
Praktische Beispiele mit REINDEX
Lassen Sie uns dies mit einem Beispiel veranschaulichen. Angenommen, wir haben eine Tabelle products und einen Index idx_product_name.
-- Beispieltabellen und Indizes erstellen CREATE TABLE products ( id SERIAL PRIMARY KEY, name VARCHAR(255) NOT NULL, price NUMERIC(10, 2) ); CREATE INDEX idx_product_name ON products (name); -- Einige Daten einfügen INSERT INTO products (name, price) SELECT 'Produkt ' || generate_series(1, 10000), random() * 100; -- Bloat simulieren durch Aktualisieren vieler Zeilen UPDATE products SET name = 'Aktualisiertes Produkt ' || id WHERE id > 5000; DELETE FROM products WHERE id BETWEEN 100 AND 200; -- Sie können nach Bloat suchen (benötigt bestimmte Erweiterungen oder Abfragen) -- Zur Demonstration gehen wir davon aus, dass Bloat aufgetreten ist. -- Einen bestimmten Index neu erstellen REINDEX INDEX idx_product_name; -- Alle Indizes einer Tabelle neu erstellen REINDEX TABLE products; -- Alle Indizes in einer Datenbank neu erstellen (kann sehr ressourcenintensiv sein) REINDEX DATABASE my_database;
Wichtige Überlegungen zu REINDEX:
- Sperren:
REINDEXkann eineACCESS EXCLUSIVE-Sperre für den Index (oder die Tabelle oder die Datenbank) erwerben, die während der Ausführung Lese- und Schreibzugriffe auf die betroffenen Objekte verhindert. Dieser Ausfall kann für Hochverfügbarkeitssysteme inakzeptabel sein. CONCURRENTLYOption: Für Indizes von Tabellen bietet PostgreSQLREINDEX INDEX CONCURRENTLYundREINDEX TABLE CONCURRENTLYan. Diese Option ermöglicht die Neuerstellung des Indexes, ohne eineACCESS EXCLUSIVE-Sperre zu erfordern, wodurch sie für Produktionsumgebungen geeignet ist. Sie führt zwei Tabellenscans durch und benötigt mehr Zeit und temporären Festplattenspeicher.
Dieser nebenläufig erstellte Index ersetzt das Original, ohne gleichzeitige DML-Operationen zu blockieren. Beachten Sie, dassREINDEX INDEX CONCURRENTLY idx_product_name;CONCURRENTLYfürREINDEX DATABASEoderREINDEX SYSTEMnicht verfügbar ist.
VACUUM FULL: Speicherplatz in Tabellen und Indizes zurückgewinnen
VACUUM FULL ist ein wesentlich aggressiverer Befehl als VACUUM. Während ein reguläres VACUUM tote Tupel lediglich zur Wiederverwendung markiert, baut VACUUM FULL die gesamte Tabelle und ihre zugehörigen Indizes von Grund auf neu auf, indem es eine völlig neue Version der Tabelle schreibt. Dies gibt effektiv den gesamten Speicherplatz für tote Tupel zurück, sowohl im Tabellendatensatz als auch in seinen Indizes, und verdichtet die Tabelle auf der Festplatte.
Wie VACUUM FULL funktioniert
VACUUM FULL funktioniert wie folgt:
- Erstellung einer neuen Tabellendatei: Es schreibt eine neue Version der Tabelle, die nur aktive Zeilen enthält, an einen neuen Speicherort auf der Festplatte.
- Neuerstellung von Indizes: Als Teil dieses Prozesses werden auch alle zugehörigen Indizes neu erstellt, um auf die neue Tabellenstruktur zu verweisen.
- Ersetzen der alten Tabelle: Sobald die neue Tabelle und ihre Indizes fertiggestellt sind, werden die alte Tabelle und ihre zugehörigen Indexdateien gelöscht.
Wann VACUUM FULL verwendet werden sollte
VACUUM FULL ist ein stumpfes Werkzeug und sollte aufgrund seiner schwerwiegenden Sperrauswirkungen sparsam eingesetzt werden. Sein Hauptanwendungsfall ist:
- Schwerer Tabellen-Bloat: Wenn eine Tabelle selbst eine massive Menge an totem Speicherplatz angesammelt hat, den ein reguläres
VACUUM(auch autovacuum) nicht effizient zurückgewinnen kann. Hierbei geht es weniger um Index-Bloat als vielmehr um den gesamten Tabellenspeicher. - Spezifische Speicherszenarien: In sehr seltenen Fällen, wenn Sie sofort Festplattenspeicher zurückgewinnen müssen und sicher sind, dass ein langer Ausfall akzeptabel ist.
Praktische Beispiele mit VACUUM FULL
Unter Verwendung unseres products-Tabellenbeispiels:
-- Signifikanten Tabellen- und Index-Bloat simulieren -- (z. B. einen großen Teil der Zeilen löschen, ohne dass autovacuum ausgeführt wird) DELETE FROM products WHERE id > 7000; -- Jetzt VACUUM FULL ausführen VACUUM FULL products;
Wichtige Überlegungen zu VACUUM FULL:
- Sperren:
VACUUM FULLerwirbt eineACCESS EXCLUSIVE-Sperre für die verarbeitete Tabelle. Das bedeutet, dass auf dieser Tabelle (und implizit ihren Indizes) keine Lese- oder Schreibzugriffe erfolgen können, bisVACUUM FULLabgeschlossen ist. Bei großen Tabellen kann dieser Ausfall Stunden dauern, was ihn für Produktionssysteme im Allgemeinen ungeeignet macht. - Festplattenspeicher: Es benötigt temporären Festplattenspeicher, der ungefähr der Größe der verarbeiteten Tabelle entspricht, da es eine neue Kopie der Tabelle erstellt.
- Indexauswirkung: Obwohl
VACUUM FULLals Nebeneffekt des Neuerstellens der Tabelle ebenfalls Index-Bloat beseitigt, konzentriert es sich hauptsächlich auf Tabellen-Bloat. Wenn nur Index-Bloat das Problem ist, istREINDEX(insbesondereCONCURRENTLY) fast immer die bevorzugte Lösung. - Alternativen: Für Tabellen-Bloat sollten Sie Werkzeuge wie
pg_repack(ein Drittanbieter-Dienstprogramm) in Betracht ziehen, das Tabellen und Indizes online neu aufbauen kann, ohne über längere ZeiträumeACCESS EXCLUSIVE-Sperren zu halten.
Die Wahl zwischen REINDEX und VACUUM FULL
Die Wahl hängt vom spezifischen Problem ab, das Sie lösen möchten, und Ihrer Ausfalltoleranz:
| Merkmal | REINDEX (ohne CONCURRENTLY) | REINDEX CONCURRENTLY | VACUUM FULL |
|---|---|---|---|
| Hauptziel | Index-Bloat beseitigen, Index reparieren | Index-Bloat beseitigen, Index reparieren | Tabellen- und Index-Bloat beseitigen |
| Sperren | ACCESS EXCLUSIVE für Index | SHARE UPDATE EXCLUSIVE (kurz) | ACCESS EXCLUSIVE für Tabelle |
| Ausfallzeit | Kurzer Ausfall für Index | Minimal bis kein Ausfall | Voller Ausfall für Tabelle und ihre Indizes |
| Festplattenspeicher | Temporärer Speicher für neuen Index | Mehr temporärer Speicher, längere Laufzeit | Temporärer Speicher für die gesamte Tabelle |
| Ressourcennutzung | Moderate CPU/IO | Hohe CPU/IO | Sehr hohe CPU/IO |
| Anwendbarkeit | Einzelner Index, schnelle Behebung | Produktionssysteme, einzelner Index | Schwerer Tabellen-Bloat, Wartungsfenster |
Wann REINDEX bevorzugt werden sollte:
- Sie beobachten hauptsächlich Bloat in Ihren Indizes, nicht unbedingt in der Tabelle selbst.
- Sie müssen einen beschädigten Index reparieren.
- Sie möchten Index-Speicherparameter ändern.
- Sie benötigen minimale Ausfallzeit (verwenden Sie
CONCURRENTLY).
Wann VACUUM FULL in Betracht gezogen werden sollte (mit äußerster Vorsicht):
- Ihre Tabelle selbst ist stark aufgebläht und
VACUUM(auch autovacuum) ist nicht ausreichend. - Sie haben ein geplantes Wartungsfenster, in dem eine längere
ACCESS EXCLUSIVE-Sperre akzeptabel ist. - Sie verstehen und akzeptieren die vollständige Ausfallzeit für die Tabelle.
In den meisten modernen PostgreSQL-Bereitstellungen ist REINDEX INDEX CONCURRENTLY die bevorzugte Lösung für die Indexwartung. Wenn Tabellen-Bloat ein wiederkehrendes Problem darstellt, sollten Sie Ihre Autovacuum-Einstellungen optimieren oder externe Werkzeuge wie pg_repack prüfen, bevor Sie auf VACUUM FULL zurückgreifen.
Fazit
Die Aufrechterhaltung der Indexgesundheit ist für die Erzielung einer optimalen PostgreSQL-Leistung von größter Bedeutung. Obwohl sowohl REINDEX als auch VACUUM FULL Bloat beseitigen und Speicherplatz zurückgewinnen können, unterscheiden sie sich erheblich in ihrem Umfang, ihrem Sperrverhalten und ihren Auswirkungen auf die Systemverfügbarkeit. REINDEX ist speziell für Indizes konzipiert, und seine CONCURRENTLY-Option macht es zur bevorzugten Methode für die Online-Indexoptimierung, während VACUUM FULL auf ganze Tabellen wirkt und nur in seltenen Fällen mit hoher Ausfallzeit tolerierbar eingesetzt werden sollte. Die Wahl des richtigen Werkzeugs für die jeweilige Aufgabe stellt sicher, dass Ihre Datenbank schnell und effizient bleibt, ohne unnötige Serviceunterbrechungen.

