Meine Frage besteht aus 2 Teilen.
- Gibt es eine Möglichkeit, die anfängliche Größe einer Datenbank in PostgreSQL festzulegen?
- Wenn nicht, wie gehen Sie mit der Fragmentierung um, wenn die Datenbank mit der Zeit wächst?
Ich bin kürzlich von MSSQL zu Postgres migriert, und eines der Dinge, die wir in der MSSQL-Welt beim Erstellen einer Datenbank getan haben, war die Angabe der Anfangsgröße der Datenbank und des Transaktionsprotokolls. Dies verringert die Fragmentierung und erhöht die Leistung, insbesondere wenn die "normale" Größe der Datenbank im Voraus bekannt ist.
Die Leistung meiner Datenbank nimmt mit zunehmender Größe ab. Zum Beispiel dauert die Arbeit, die ich durchführe, normalerweise 10 Minuten. Wenn die Datenbank wächst, nimmt diese Zeit zu. Wenn Sie eine VACUUM-, VACUUM FULL- und VACUUM FULL-ANALYSE durchführen, scheint sich das Problem nicht zu lösen. Durch das Stoppen der Datenbank, das De-Fragmentieren des Laufwerks und die anschließende VACUUM FULL ANALYSE wird die Leistung meines Tests auf die ursprünglichen 10 Minuten zurückgesetzt. Dies lässt mich vermuten, dass Fragmentierung mich schmerzt.
Ich konnte keinen Verweis auf die Reservierung von Tablespace / Datenbank in Postgres finden. Entweder verwende ich die falsche Terminologie und finde nichts, oder es gibt eine andere Möglichkeit, die Fragmentierung des Dateisystems in Postgres zu verringern.
Irgendwelche Hinweise?
Die Lösung
Die gelieferten Antworten bestätigten, was ich vermutet hatte. PostgreSQL speichert die Datenbank über mehrere Dateien hinweg. Auf diese Weise kann die Datenbank ohne Fragmentierungsprobleme erweitert werden. Das Standardverhalten besteht darin, diese Dateien bis zum Rand mit Tabellendaten zu packen. Dies ist gut für Tabellen, die sich selten ändern, aber schlecht für Tabellen, die häufig aktualisiert werden.
PostgreSQL verwendet MVCC , um gleichzeitig auf Tabellendaten zuzugreifen. Bei diesem Schema wird bei jeder Aktualisierung eine neue Version der aktualisierten Zeile erstellt (dies kann über den Zeitstempel oder die Versionsnummer erfolgen, wer weiß?). Die alten Daten werden nicht sofort gelöscht, sondern zum Löschen markiert. Die tatsächliche Löschung erfolgt, wenn eine VACUUM-Operation ausgeführt wird.
Wie hängt das mit dem Füllfaktor zusammen? Der Standardfüllfaktor für Tabellen von 100 füllt die Tabellenseiten vollständig aus, was wiederum bedeutet, dass auf der Tabellenseite kein Platz für aktualisierte Zeilen vorhanden ist, dh aktualisierte Zeilen werden auf einer anderen Tabellenseite als in der ursprünglichen Zeile abgelegt. Das ist schlecht für die Leistung, wie meine Erfahrung zeigt. Da meine Übersichtstabellen sehr häufig aktualisiert werden (bis zu 1500 Zeilen / Sek.), Habe ich einen Füllfaktor von 20 festgelegt, dh 20% der Tabelle sind für eingefügte Zeilendaten und 80% für Aktualisierungsdaten. Dies mag zwar übertrieben erscheinen, aber der große Platz, der für aktualisierte Zeilen reserviert ist, bedeutet, dass die aktualisierten Zeilen auf derselben Seite wie das Original bleiben und die Tabellenseite zum Zeitpunkt der Ausführung des Autovacuum-Daemons zum Entfernen veralteter Zeilen nicht voll ist.
Um meine Datenbank zu "reparieren", habe ich Folgendes getan.
- Setzen Sie den Füllfaktor meiner Übersichtstabellen auf 20. Sie können dies zum Zeitpunkt der Erstellung tun, indem Sie einen Parameter an CREATE TABLE übergeben oder hinterher über ALTER TABLE. Ich habe den folgenden Befehl plpgsql ausgegeben:
ALTER TABLE "my_summary_table" SET (fillfactor = 20);
- Erstellte ein VACUUM FULL, da dieses eine komplett neue Version der Tabellendatei schreibt und somit implizit eine neue Tabellendatei mit dem neuen Füllfaktor schreibt .
Wenn ich meine Tests erneut durchführe, sehe ich keinen Leistungsabfall, selbst wenn die Datenbank so groß ist, wie ich es für viele Millionen Zeilen benötige.
TL; DR - Dateifragmentierung war nicht die Ursache, sondern eine Fragmentierung des Tabellenbereichs. Dies wird durch die Anpassung des Füllfaktors der Tabelle an Ihren speziellen Anwendungsfall verringert.