| PostgreSQL: Das Offizielle Handbuch | ||||
|---|---|---|---|---|
| Zurück | Schnell zurück | Schnell nach vorne | Nach vorne | |
Es gibt einige wenige routinemäßige Wartungsaufgaben, die durchgeführt werden müssen, damit ein PostgreSQL-Server problemlos laufen kann. Die hier beschriebenen Aufgaben müssen regelmäßig wiederholt werden und können leicht mit normalen Unix-Werkzeugen wie cron automatisiert werden. Aber es liegt in der Verantwortung des Datenbankadministrators, die passenden Skripts einzurichten und zu überwachen, dass sie erfolgreich ausgeführt werden.
Eine offensichtliche Wartungsaufgabe ist die regelmäßige Erstellung von Sicherungskopien der Daten. Ohne eine Sicherungskopie, die auf dem letzten Stand ist, haben Sie keine Chance, nach einer Katastrophe (Festplattenausfall, Feuer, aus Versehen eine wichtige Tabelle gelöscht usw.) Ihre Daten wiederherstellen zu können. Die in PostgreSQL verfügbaren Datensicherungs- und -wiederherstellungsmechanismen werden ausführlich in Kapitel 22 besprochen.
Die andere Hauptaufgabe der Wartung ist das regelmäßige Vacuum (zu Deutsch „Staubsaugen“) der Datenbank. Dieses Thema wird in Abschnitt 21.1 besprochen.
Noch etwas, das regelmäßige Aufmerksamkeit erfordert, ist die Verwaltung der Logdateien. Das wird in Abschnitt 21.3 besprochen.
Verglichen mit anderen Datenbankprodukten hat PostgreSQL einen geringen Wartungsaufwand. Wenn Sie den sich stellenden Aufgaben nichtsdestoweniger die angebrachte Aufmerksamkeit widmen, dann werden Sie dadurch Ihre Arbeit mit dem System angenehmer und produktiver gestalten.
In PostgreSQL muss aus mehreren Gründen regelmäßig der Befehl VACUUM ausgeführt werden:
Um den von aktualisierten oder gelöschten Zeilen belegten Speicherplatz wiederzugewinnen.
Um die vom PostgreSQL-Anfrageplaner verwendeten Datenstatistiken zu aktualisieren.
Um sich gegen den Verlust sehr alter Daten durch Überlauf der Transaktionsnummern zu schützen.
Die Häufigkeit und das Ausmaß der aus jedem dieser Gründe ausgeführten VACUUM-Operationen hängt von der individuellen Situation ab. Datenbankadministratoren müssen daher diese Angelegenheiten verstehen und eine passende Wartungsstrategie entwickeln. Dieser Abschnitt konzentriert sich auf das Erklären der allgemeinen Problematik; Einzelheiten der Befehlssyntax und so weiter finden Sie auf der VACUUM-Referenzseite.
Seit PostgreSQL 7.2 kann die Standardform von VACUUM parallel mit normalen Datenbankoperationen (Anfragen, Einfügen, Aktualisieren, Löschen, aber nicht Änderungen an der Tabellendefinition) laufen. Routinemäßiges Vacuum ist daher kein so großer Einschnitt in die Datenbankoperation mehr, wie es in früheren Versionen war, und es ist auch nicht mehr so wichtig, es an Tageszeiten mit niedriger Belastung auszuführen.
In PostgreSQL wird bei einem UPDATE oder DELETE einer Zeile die alte Zeilenversion nicht sofort entfernt. Dieses Verhalten ist notwendig um das Multiversionssystem für den Mehrbenutzerbetrieb zu ermöglichen (siehe Kapitel 12): Die Zeilenversion darf nicht gelöscht werden, solange sie potentiell noch in anderen Transaktionen sichtbar ist. Aber irgendwann wird sich keine Transaktion mehr für eine alte oder gelöschte Zeilenversion mehr interessieren. Der davon belegte Platz muss für die Wiederverwendung durch neue Zeilen wiedergewonnen werden, um zu verhindern, dass die Speicherplatzanforderungen ins Unendliche wachsen. Das wird von VACUUM erledigt.
Eine Tabelle, in der oft aktualisiert oder gelöscht wird, muss also offensichtlich öfter „gevacuumt“ werden als Tabellen, die selten verändert werden. Es könnte hilfreich sein, einen cron-Auftrag zu registrieren, der nur in ausgewählten Tabellen VACUUM ausführt und Tabellen, von denen bekannt ist, dass sie sich nicht oft ändern, auslässt. Aber das ist wahrscheinlich nur sinnvoll, wenn Sie große oft aktualisierte und große selten aktualisierte Tabellen haben, denn der zusätzliche Aufwand um VACUUM in einer kleinen Tabelle auszuführen ist nicht groß genug um sich darüber Gedanken zu machen.
Die Standardform vom VACUUM wird am besten mit dem Ziel angewendet, einen relativ stabilen Festplattenplatzverbrauch zu erhalten. Die Standardform findet alte Zeilenversionen und macht deren Platz für die Wiederverwendung in der Tabelle verfügbar, aber sie versucht nicht zu sehr die Tabellendatei zu verkürzen und den Platz an das Betriebssystem zurückzugeben. Wenn Sie Platz an das Betriebssystem zurückgeben wollen, dann können Sie VACUUM FULL verwenden -- aber welchen Sinn hat es, Festplattenplatz an das Betriebssystem zurückzugeben, der sowieso bald wieder verwendet werden muss? Einigermaßen häufige VACUUM-Läufe in der Standardform sind für oft aktualisierte Tabellen ein besserer Ansatz als seltene VACUUM FULL-Läufe.
Für die meisten Anwender wird empfohlen, einmal am Tag, wenn wenig Betrieb ist, VACUUM für die ganze Datenbank auszuführen und als Ergänzung wenn nötig häufigeres Vacuum von oft aktualisierten Tabellen. (Wenn Sie mehrere Datenbanken in einem Cluster haben, vergessen Sie nicht, VACUUM in jeder einzelnen auszuführen; das Programm vacuumdb kann da hilfreich sein.) Verwenden Sie das einfache VACUUM, nicht VACUUM FULL, für routinemäßiges Vacuum zur Platzwiedergewinnung.
VACUUM FULL ist zu empfehlen, wenn Sie wissen, dass Sie die Mehrzahl der Zeilen in einer Tabelle gelöscht haben, so dass die stabile Größe der Tabelle mit dem aggressiveren Ansatz von VACUUM FULL erheblich verringert werden kann.
Wenn Sie eine Tabelle haben, deren Inhalt ab und zu komplett gelöscht wird, sollten Sie in Erwägung ziehen, das mit TRUNCATE zu tun anstatt DELETE gefolgt von VACUUM zu verwenden.
Der PostgreSQL-Anfrageplaner benötigt statistische Informationen über den Inhalt der Tabellen um gute Pläne für Anfragen erzeugen zu können. Diese Statistiken werden vom Befehl ANALYZE zusammengetragen, der alleine oder als zusätzlicher Schritt in VACUUM aufgerufen werden kann. Es ist wichtig, einigermaßen genaue Statistiken zu haben, ansonsten kann die schlechte Wahl von Plänen die Datenbankleistung beeinträchtigen.
Häufiges Aktualisieren der Statistiken ist, wie beim Vacuum zur Platzgewinnung, für oft aktualisierte Tabellen nützlicher als für selten aktualisierte. Aber selbst bei oft aktualisierten Tabellen muss es nicht unbedingt notwendig sein, die Statistiken zu aktualisieren, wenn sich die statistische Verteilung kaum verändert. Am einfachsten ist es, sich zu überlegen, wie sehr sich die Minimal- und Maximalwerte in den Tabellenspalten ändern. Eine timestamp-Spalte, zum Beispiel, die die Zeit der letzten Zeilenaktualisierung enthält, hat einen ständig steigenden Maximalwert; so eine Spalte benötigt wahrscheinlich häufigeres Statistik Aktualisieren als, sagen wir, eine Spalte, die speichert, welche URLs einer Website abgerufen wurden. Die URL-Spalte mag sich vielleicht genauso oft ändern, aber die statistische Verteilung der Werte ändert sich wahrscheinlich nur sehr langsam.
ANALYZE kann man auch für bestimmte Tabellen und sogar nur für bestimmte Spalten einer Tabelle ausgeführt werden, so dass man einige Statistiken öfter als andere aktualisieren kann, wenn es die Anwendung erfordert. In der Praxis ist der Nutzen dieser Fähigkeit allerdings zweifelhaft. Seit PostgreSQL 7.2 ist ANALYZE sogar bei großen Tabellen ziemlich schnell, weil es nur eine zufällige Auswahl der Tabellenzeilen verwendet, anstatt jede einzelne Zeile zu lesen. Es ist also wahrscheinlich viel einfacher, es einfach ab und zu für die ganze Datenbank auszuführen.
Tipp: Obwohl ein verschieden häufiges ANALYZE für verschiedene Spalten in der Regel nicht sehr produktiv ist, kann es sehr wohl sinnvoll sein, das Ausmaß der gesammelten Statistiken einzustellen. Spalten, die oft in WHERE-Klauseln verwendet werden und sehr unregelmäßige Datenverteilungen haben, könnten ein detaillierteres Datenhistogramm gebrauchen als andere. Sehen Sie bei ALTER TABLE SET STATISTICS nach.
Für die meisten Anwender wird empfohlen, ANALYZE einmal am Tag, wenn wenig Betrieb ist, für die ganze Datenbank auszuführen; das kann am besten mit einem nächtlichen VACUUM verbunden werden. Anwender mit Tabellenstatistiken, die sich relativ langsam verändern, könnten jedoch zu der Feststellung gelangen, dass das übertrieben ist und dass weniger häufige ANALYZE-Läufe ausreichend sind.
Im MVCC-System von PostgreSQL spielt das Vergleichen von Transactionsnummern (XID) eine wichtige Rolle: Eine Zeilenversion mit einer Einfügungs-XID, die größer als die XID der aktuellen Transaktion ist, ist „in der Zukunft“ und sollte für die aktuelle Transaktion nicht sichtbar sein. Da aber Transaktionsnummern eine begrenzte Größe haben (gegenwärtig 32 Bits), kann es in einem Cluster, der eine lange Zeit läuft (mehr als 4 Milliarden Transaktionen), zum Transaktionsnummernüberlauf kommen: Der XID-Zähler fängt wieder bei null an und plötzlich werden Transaktion aus der Vergangenheit so aussehen, als ob sie in der Zukunft wären, was bedeutet, dass deren Ergebnisse unsichtbar werden. Kurz gesagt würden Sie die totale Datenverlustkatastrophe erleben. (Die Daten sind eigentlich noch da, aber das ist sicherlich nicht sehr beruhigend, wenn man nicht auf sie zugreifen kann.)
Vor PostgreSQL 7.2 war die einzige Verteidigung gegen Transaktionsnummernüberlauf, dass man mindestens alle 4 Milliarden Transaktionen initdb neu ausführt. Dieser Weg war für Anwendungen mit viel Betrieb nicht zufrieden stellend und daher wurde eine bessere Lösung erdacht. Der neue Ansatz erlaubt es, dass der Server endlos laufen kann, ohne initdb oder irgendeinen Neustart. Der Preis dafür ist diese Wartungsanforderung: jede Tabelle in der Datenbank muss mindestens einmal alle eine Milliarde Transaktionen gevacuumt werden.
In der Praxis ist das keine besonders umständliche Forderung, aber da die Konsequenz, wenn man sich nicht daran hält, kompletter Datenverlust sein kein (nicht nur verschwendeter Speicherplatz oder schlechte Leistung), wurden einige besondere Vorkehrungen errichtet, um den Datenbankadministratoren zu helfen die Zeit seit dem letzten VACUUM zu verfolgen. Der Rest dieses Abschnitts gibt dazu Einzelheiten.
Der neue Ansatz beim XID-Vergleich kennt zwei besondere XIDs, Nummer 1 und 2 (BootstrapXID und FrozenXID). Diese beiden XIDs werden immer als älter als alle anderen XIDs betrachtet. Normale XIDs (die größer als 2) werden mit Arithmetik modulo 231 verglichen. Das bedeutet, dass es für jede normale XID zwei Milliarden XIDs die „älter“ und zwei Milliarden die „neuer“ sind gibt; anders ausgedrückt ist der Raum der normalen XIDs kreisförmig ohne Endpunkte. Wenn daher eine Zeilenversion mit einer bestimmten XID erzeugt worden ist, dann erscheint sie für die nächsten zwei Milliarden Transaktionen als „in der Vergangenheit“, egal welche normale XID es ist. Wenn die Zeilenversion nach mehr als zwei Milliarden Transaktionen noch existiert, dann erscheint sie plötzlich in der Zukunft zu sein. Um Datenverlust zu vermeiden muss alten Zeilenversionen irgendwann die XID FrozenXID zugewiesen werden (sie müssen also quasi „eingefroren“ werden), bevor Sie zwei Milliarden Transaktionen alt werden. Wenn ihnen einmal diese besondere XID zugewiesen wurde, dann werden Sie für alle normalen Transaktionen als „in der Vergangenheit“ erscheinen, ungeachtet der Überlaufproblematik, und daher werden sie bis zum Löschen gültig bleiben, egal wie lange das sein wird. Diese Neuzuweisung der XID wird von VACUUM erledigt.
Die normale Strategie von VACUUM ist es, die FrozenXID jeder Zeilenversion zuzuweisen, deren XID mehr als eine Milliarde Transaktionen in der Vergangenheit liegt. Dadurch wird die originale Einfügungs-XID so lange erhalten, bis sie wahrscheinlich nicht mehr von Interesse ist. (Die meisten Zeilenversionen werden wahrscheinlich entstehen und verschwinden ohne jemals „eingefroren“ zu werden.) Mit dieser Strategie ist der höchste sichere Zeitraum zwischen VACUUM-Läufen für eine Tabelle genau eine Milliarde Transaktionen: Wenn Sie länger warten, dann kann es sein, dass eine Zeilenversion, die beim letzte Mal noch nicht ganz alt genug war um umnummeriert zu werden, jetzt zu alt ist und in der Zukunft liegt. Das hieße, sie ist für Sie verloren. (Natürlich wird sie nach weiteren zwei Milliarden Transaktionen wieder auftauchen, aber das hilft Ihnen sicher nicht weiter.)
Da regelmäßige VACUUM-Läufe aus den schon beschriebenen Gründen sowieso nötig sind, ist es unwahrscheinlich, dass eine Tabelle eine ganze Milliarde Transaktionen in diese nicht mit einbezogen würde. Um aber Administratoren zu helfen, dass diese Beschränkung eingehalten wird, speichert VACUUM Transaktionsnummernstatistiken in der Systemtabelle pg_database. Insbesondere wird die Spalte datfrozenxid der zu einer Datenbank gehörigen pg_database-Zeile am Ende jeder datenbankweiten VACUUM-Operation (d.h. VACUUM, das keine bestimmte Tabelle benennt) aktualisiert. Der in diesem Feld gespeicherte Wert ist quasi die vom letzten VACUUM verwendete Einfriergrenze: Alle normalen XIDs, die älter als der Grenzwert sind, sind in jener Datenbank garantiert durch FrozenXID ersetzt worden. Ein bequemer Weg, sich diese Information anzusehen, ist folgende Anfrage auszuführen:
SELECT datname, age(datfrozenxid) FROM pg_database;
Die Spalte age misst die Anzahl der Transaktionen von jenem Grenzwert bis zur XID der aktuellen Transaktion.
Mit der Standardstrategie fängt die Spalte age in einer Datenbank direkt nach einem VACUUM bei einer Milliarde an. Wenn age sich zwei Milliarden nähert, dann muss VACUUM bald wieder ausgeführt werden um Überlaufprobleme zu vermeiden. Wir empfehlen, in jeder Datenbank mindestens alle halbe Milliarde (500 Millionen) Transaktionen VACUUM auszuführen, damit reichlich Sicherheitsspielraum bleibt. Um Ihnen zu helfen, dieser Regel zu folgen, gibt jedes datenbankweite VACUUM automatisch eine Warnung aus, wenn irgendein pg_database-Eintrag für age mehr als 1,5 Milliarden Transaktionen zeigt, zum Beispiel:
play=# VACUUM;
WARNING: Some databases have not been vacuumed in 1613770184 transactions.
Better vacuum them within 533713463 transactions,
or you may have a wraparound failure.
VACUUM
VACUUM mit der Option FREEZE verfolgt eine aggressivere Strategie beim Einfrieren: Zeilenversionen werden eingefroren, wenn sie alt genug sind um in allen offenen Transaktionen gültig zu sein. Insbesondere gilt, wenn VACUUM FREEZE in einer ansonsten gerade unbenutzten Datenbank durchgeführt wird, dann ist garantiert, dass alle Zeilenversionen in dieser Datenbank eingefroren werden. Wenn dann die Datenbank nicht weiter verändert wird, dann muss sie auch nicht mehr gevacuumt werden um Problemen mit Transaktionsnummernüberlauf zu begegnen. Diese Technik wird von initdb verwendet um die Datenbank template0 vorzubereiten. Sie sollte auch für Datenbanken verwendet werden, bei denen in pg_database datallowconn = false gesetzt wird, da man in Datenbanken, mit denen man nicht verbinden kann, auch kein VACUUM ausführen kann. Beachten Sie, dass VACUUM für Datenbanken mit datallowconn = false keine automatischen Warnungen über einen zu langen Zeitraum seit dem letzten VACUUM ausgibt, damit für solche Datenbanken keine falschen Warnungen ausgegeben werden; daher müssen Sie selbst darauf achten, dass solche Datenbanken ordnungsgemäß eingefroren werden.
| Zurück | Zum Anfang | Nach vorne |
| Einbyte-Zeichensatz-Konvertierung | Nach oben | Routinemäßiges Reindizieren |