TOAST Tischwachstum außer Kontrolle - FULLVAC macht nichts

9

Vor kurzem habe ich einen PostgreSQL 8.2.11-Server auf 8.4 aktualisieren lassen, um die Autovakuum-Funktionen zu nutzen und mit 30 anderen PGSQL-Servern in Einklang zu stehen. Dies wurde von einer separaten IT-Gruppe durchgeführt, die die Hardware verwaltet, sodass wir bei anderen Upgrades keine große Auswahl haben (9+ werden für eine Weile nicht angezeigt). Der Server befindet sich in einer sehr geschlossenen Umgebung (isoliertes Netzwerk, eingeschränkte Root-Rechte) und läuft unter RHEL5.5 (i686). Nach dem Upgrade ist die Datenbank ständig auf 5 bis 6 GB pro Tag angewachsen. Normalerweise ist die Datenbank insgesamt ~ 20 GB groß. Derzeit sind es ~ 89 GB. Wir haben ein paar andere Server, die äquivalente Datenbanken ausführen und die Datensätze über eine Drittanbieteranwendung miteinander synchronisieren (einer, auf den ich keinen Zugriff auf das Innenleben habe). Die anderen Datenbanken haben ~ 20 GB, wie sie sein sollten.

Wenn Sie das folgende SQL ausführen, ist es ziemlich offensichtlich, dass es ein Problem mit einer bestimmten Tabelle gibt, insbesondere mit der TOAST-Tabelle.

SELECT nspname || '.' || relname AS "relation",
    pg_size_pretty(pg_relation_size(C.oid)) AS "size"
  FROM pg_class C
  LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace)
  WHERE nspname NOT IN ('pg_catalog', 'information_schema')
  ORDER BY pg_relation_size(C.oid) DESC
  LIMIT 20;

Welches produziert:

              Beziehung | Größe  
------------------------------------ + ---------  
  pg_toast.pg_toast_16874 | 89 GB  
  paars00.warmstates | 1095 MB  
  ...  
(20 Zeilen)

Diese TOAST-Tabelle ist für eine Tabelle namens "Zeitreihen" vorgesehen, in der große Datensätze von Blobbed-Daten gespeichert werden. Ein SUM(LENGTH(blob)/1024./1024.)aller Datensätze in Zeitreihen ergibt ~ 16 GB für diese Spalte. Es sollte keinen Grund geben, warum die TOAST-Tabelle dieser Tabelle so groß sein sollte wie sie ist.

Ich habe eine durchgeführt VACUUM FULL VERBOSE ANALYZE timeseries, und das Vakuum läuft ohne Fehler vollständig ab.

INFO: Staubsaugen "pg_toast.pg_toast_16874"
INFO: "pg_toast_16874": 22483 entfernbare, 10475318 nicht entfernbare Zeilenversionen in 10448587 Seiten gefunden
DETAIL: 0 tote Zeilenversionen können noch nicht entfernt werden.
Nicht entfernbare Zeilenversionen sind zwischen 37 und 2036 Byte lang.
Es gab 20121422 nicht verwendete Elementzeiger.
Der gesamte freie Speicherplatz (einschließlich der Versionen für entfernbare Zeilen) beträgt 0 Byte. 4944885 Seiten sind oder werden leer, einschließlich 0 am Ende der Tabelle. 4944885 Seiten mit 0 freien Bytes sind potenzielle Verschiebungsziele.
CPU 75,31 s / 29,59 u s verstrichen 877,79 s.
INFO: Der Index "pg_toast_16874_index" enthält jetzt 10475318 Zeilenversionen auf 179931 Seiten.
DETAIL: 23884 Indexzeilenversionen wurden entfernt.
101623 Indexseiten wurden gelöscht, 101623 sind derzeit wiederverwendbar.
CPU 1,35 s / 2,46 u s verstrichen 21,07 s.

REINDEXed die Tabelle, die etwas Speicherplatz freigab (~ 1 GB). Ich kann die Tabelle nicht CLUSTEREN, da auf der Festplatte nicht genügend Speicherplatz für den Prozess vorhanden ist, und ich warte darauf, die Tabelle vollständig neu zu erstellen, da ich herausfinden möchte, warum sie so viel größer ist als die entsprechenden Datenbanken.

Ich habe hier eine Abfrage aus dem PostgreSQL-Wiki ausgeführt - "Show Database Bloat" , und das bekomme ich:

aktuelle_Datenbank | Schemaname | Tabellenname | tbloat | verschwendete Bytes | iname | ibloat | Wastibytes  
----------------- + ------------ + ------------------- ------------- + -------- + ------------- + ------------- -------------------- + -------- + --------------  
ptrdb04 | paars00 | Zeitreihen | 1,0 | 0 | idx_timeseries_synchlevel | 0.0 | 0  
ptrdb04 | paars00 | Zeitreihen | 1,0 | 0 | idx_timeseries_localavail | 0.0 | 0  
ptrdb04 | paars00 | Zeitreihen | 1,0 | 0 | idx_timeseries_expirytime | 0.0 | 0  
ptrdb04 | paars00 | Zeitreihen | 1,0 | 0 | idx_timeseries_expiry_null | 0.0 | 0  
ptrdb04 | paars00 | Zeitreihen | 1,0 | 0 | uniq_localintid | 0.0 | 0  
ptrdb04 | paars00 | Zeitreihen | 1,0 | 0 | pk_timeseries | 0,1 | 0  
ptrdb04 | paars00 | idx_timeseries_expiry_null | 0,6 | 0 | ? | 0.0 | 0

Es sieht so aus, als würde die Datenbank diesen Speicherplatz überhaupt nicht als "leer" betrachten, aber ich sehe nur nicht, woher der gesamte Speicherplatz kommt!

Ich vermute, dass dieser Datenbankserver beschließt, 4-5x so viel Speicherplatz zu verwenden, um dieselben Datensätze zu speichern, die von den anderen Datenservern abgerufen wurden. Meine Frage lautet: Gibt es eine Möglichkeit, die physische Festplattengröße einer Zeile zu überprüfen? Ich möchte die Größe einer Zeile in dieser Datenbank mit einer anderen "gesunden" Datenbank vergleichen.

Vielen Dank für jede Hilfe, die Sie leisten können!

UPDATE 1

Am Ende habe ich die Tabelle aufgrund ihrer Größe aus einem ausgelagerten Schema neu erstellt (konnte sie nicht für einen weiteren Tag alleine lassen). Nach dem Synchronisieren der Daten über den Software-Synchronisierungsprozess betrug die TOAST-Tabelle ~ 35 GB. Ich konnte jedoch nur ~ 9 GB davon aus dieser Blob-Spalte entnehmen, die in Bezug auf die Werte am längsten sein sollte. Ich bin mir nicht sicher, woher die anderen 26 GB kommen. CLUSTERed, VACUUM FULLed und REINDEXed ohne Erfolg. Die postgresql.conf- Dateien zwischen dem lokalen und dem Remote-Datenserver sind genau gleich. Gibt es einen Grund, warum diese Datenbank versucht, jeden Datensatz mit einem größeren Speicherplatz auf der Festplatte zu speichern?

UPDATE 2 - Behoben

Ich habe mich schließlich entschlossen, die Datenbank von Grund auf neu zu erstellen und sogar die PostgreSQL84-Pakete auf dem System neu zu installieren. Der Datenbankpfad wurde neu initialisiert und die Tablespaces wurden gelöscht. Der Software-Synchronisierungsprozess eines Drittanbieters füllte die Tabellen neu und die endgültige Größe betrug ~ 12 GB ! Leider hilft dies in keiner Weise, die genaue Ursache des Problems zu lösen. Ich werde es mir ein oder zwei Tage lang ansehen und feststellen, ob es wesentliche Unterschiede bei der Behandlung der TOAST-Tabelle durch die revitalisierte Datenbank gibt, und diese Ergebnisse hier veröffentlichen.

Beziehungsgröße


ptrdb04=> SELECT nspname || '.' || relname AS "relation",
ptrdb04->     pg_size_pretty(pg_relation_size(C.oid)) AS "size"
ptrdb04->   FROM pg_class C
ptrdb04->   LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace)
ptrdb04->   WHERE nspname NOT IN ('pg_catalog', 'information_schema')
ptrdb04->   ORDER BY pg_relation_size(C.oid) DESC
ptrdb04->   LIMIT 2;

        Beziehung          |   Größe   
 ------------------------- + --------- 
 pg_toast . pg_toast_17269 | 18 GB 
 paars00 . warmstates        | 1224 MB
 ( 2 Zeilen )  

VACUUM VERBOSE ANALYZE timeseries;

INFO: "timeseries": 12699 entfernbare, 681961 nicht entfernbare Zeilenversionen in 58130 von 68382 Seiten gefunden
DETAIL: 0 Dead Row-Versionen können noch nicht entfernt werden.
Es gab 105847 nicht verwendete Elementzeiger.
0 Seiten sind völlig leer.
CPU 0,83 s / 2,08 u s verstrichen 33,36 s.
INFO: Staubsaugen "pg_toast.pg_toast_17269"
INFO: Gescannter Index "pg_toast_17269_index" zum Entfernen von 2055849-Zeilenversionen
DETAIL: CPU 0,37 s / 2,92 u s verstrichen 13,29 s.
INFO: "pg_toast_17269": 2055849 Zeilenversionen auf 518543 Seiten entfernt
DETAIL: CPU 8,60 s / 3,21 u s verstrichen 358,42 s.
INFO: Der Index "pg_toast_17269_index" enthält jetzt 7346902 Zeilenversionen auf 36786 Seiten
DETAIL: 2055849 Indexzeilenversionen wurden entfernt.
10410 Indexseiten wurden gelöscht, 5124 sind derzeit wiederverwendbar.
CPU 0,00 s / 0,00 u s verstrichen 0,01 s.
INFO: "pg_toast_17269": 1286128 entfernbare, 2993389 nicht entfernbare Zeilenversionen in 1257871 von 2328079 Seiten gefunden
DETAIL: 0 Dead Row-Versionen können noch nicht entfernt werden.
Es gab 18847 unbenutzte Artikelzeiger.
0 Seiten sind völlig leer.
CPU 26,56 s / 13,04 u s verstrichen 714,97 s.
INFO: Analyse von "paars00.timeseries"
INFO: "Zeitreihen": 30000 von 68382 Seiten gescannt, die 360192 lebende Zeilen und 0 tote Zeilen enthalten; 30000 Zeilen in der Stichprobe, 821022 geschätzte Gesamtzeilen

Der einzige spürbare Unterschied nach dem Wiederherstellen (außer der Festplattennutzung) ist

INFO: "pg_toast_17269": 1286128 entfernbare, 2993389 nicht entfernbare Zeilenversionen gefunden
wie @CraigRinger in einem Kommentar erwähnt. Die Anzahl der nicht entfernbaren Zeilen ist viel kleiner als zuvor.

Neue Frage: Können andere Tabellen die Größe einer anderen Tabelle beeinflussen? (über Fremdschlüssel und dergleichen) Die Neuerstellung der Tabelle hat nichts bewirkt, aber die Neuerstellung der gesamten Datenbank hat das Problem behoben.

BrM13
quelle
Warum haben Sie nicht direkt auf 9.2 aktualisiert? Es hat noch mehr Verbesserungen im Vakuumbereich als 8.4 (und 8.4 wird sowieso nächstes Jahr EOL)
a_horse_with_no_name
Ich habe den Beitrag aktualisiert. Das Upgrade wurde nicht von unserem Shop und nicht unbedingt von unserer Anfrage durchgeführt. Leider haben wir diese Option für ein Upgrade auf 9+ nicht.
BrM13
OK. Ich wollte nur sicherstellen, dass Sie das Offensichtliche nicht übersehen;)
a_horse_with_no_name

Antworten:

9

Diese:

INFO: "pg_toast_16874": found 22483 removable, 10475318 nonremovable row versions in 10448587 pages 22483 removable, 10475318 nonremovable row versions in 10448587 pages

schlägt vor, dass das zugrunde liegende Problem darin besteht, dass diese Zeilen immer noch von etwas "gesehen" werden können, sodass sie nicht entfernt werden können.

Die Kandidaten dafür sind:

  • Verlorene vorbereitete Transaktionen. Überprüfen Sie pg_catalog.pg_prepared_xacts; es sollte leer sein. Auch laufen SHOW max_prepared_transactions; es sollte Null melden.

  • Lang laufende Sitzungen mit einer offenen, inaktiven Transaktion. In PostgreSQL 8.4 und höher sollte dies nur ein Problem für SERIALIZABLETransaktionen sein. Suchen Sie pg_catalog.pg_stat_activitynach <IDLE> in transactionSitzungen.

Höchstwahrscheinlich haben Sie einen Client, der Transaktionen während langer Leerlaufzeiten nicht festschreibt oder zurücksetzt.

Wenn sich herausstellt, dass dies nicht der Fall ist, würde ich als Nächstes eine Summe octet_sizeder einzelnen Spalten der interessierenden Tabelle erstellen . Vergleichen Sie das mit dem pg_relation_sizeTisch und seinem TOASTBeistelltisch. Wenn es einen großen Unterschied gibt, wird der Speicherplatz wahrscheinlich durch nicht mehr sichtbare Zeilen belegt, und Sie haben wahrscheinlich Probleme mit dem Aufblähen von Tabellen. Wenn sie sich ziemlich ähnlich sind, können Sie die Platznutzung eingrenzen, indem Sie die Oktettgrößen pro Spalte aufsummieren, die oberen 'n' Werte usw. erhalten.

Craig Ringer
quelle
1) pg_prepared_xacts und max_prepared_transactions waren tatsächlich leer. 2) Es gibt definitiv einige IDLE-Transaktionen, aus SELECT * FROM pg_stat_activity WHERE current_query LIKE '<IDLE>%';denen etwa 30-40 Ergebnisse hervorgehen. Dies scheint jedoch ziemlich normal zu sein. Ich habe ein paar "gesunde" Server überprüft, und sie waren gleich.
BrM13
3) Hier ist was ich getan habe. Durchlaufen von Zeitreihenspalten, wobei octet_length (Spalte) abgerufen wird. Multiplizierte jeden Wert mit der Zeilenzahl und summierte sie. Für Zeitreihen erhielt ich ~ 430 MB (in der Nähe der 493 MB von pg_relation_size) und 438 MB für die TOAST-Tabelle (unter Verwendung der Spalten chunk_id, chunk_seq, chunk_data). Die Schätzungen sehen korrekt aus, und die TOAST-Tabelle ist um etwa 2 Größenordnungen (heute 60 GB) von der relationsgröße entfernt. Es sieht so aus, als hätte ich Aufblähen, aber nicht die traditionelle Art (unbenutztes Aufblähen). Andernfalls sollte sich ein FULLVAC um das Problem kümmern.
BrM13
@Brad Idle - Sitzungen sind in Ordnung, es ist nur Sitzungen im Leerlauf mit offenen Transaktionen that're ein Problem, das heißt <IDLE> in transaction, und nur dann , wenn sie haben (a) war im Leerlauf für eine Weile , und (b) verwendet SERIALIZABLEIsolation oder Sie sind auf 8,3 oder älter.
Craig Ringer
@Brad Es ist interessant, dass nur die TOASTTabelle aufgebläht zu sein scheint. Übrigens, wenn Sie VACUUM FULLviel auf einem Server vor 9.0 verwendet haben, möchten Sie, REINDEXwie VACUUM FULLbei diesen Versionen, ein erhebliches Aufblähen des Index verursachen. Ich frage mich jetzt, ob jemand ein Absurdes FILLFACTORauf den Toasttisch gelegt hat, obwohl das Sie nicht über den 10-fachen Platzverbrauch hinausgehen lassen sollte.
Craig Ringer
Vielen Dank für die IDLE-Klarstellung. Ich dachte, das hast du gemeint, aber es ist gut, es sicher zu wissen. Für FILLFACTOR wird in der Tabelle die Standardeinstellung verwendet. Zu Ihrer Information - Gemäß der Dokumentation zu 8.4 CREATE TABLE ist der Standardwert 100, und Sie können keinen FILLFACTOR für die TOAST-Tabelle festlegen.
BrM13
0

Ich habe keine Ahnung, warum es aufgebläht ist. Aber ich habe etwas gesucht und vielleicht hat dieser Link einen Einblick: http://postgresql.1045698.n5.nabble.com/A-154-GB-table-swelled-to-527-GB-on-the-Slony-slave -How-to-compact-it-td5543034.html ... Es ist nicht Ihre genaue Situation, aber vielleicht ist es nah genug, um Ihnen zu helfen, dem Phantom -Aufblähen auf den Grund zu gehen.

Ich denke jedoch, dass die einzige Möglichkeit, diese Tabelle zu diesem Zeitpunkt zu komprimieren, darin besteht, sie zu CLUSTEREN. Da Sie wenig Speicherplatz haben, ist dies ein Problem.

Hier ist mein Vorschlag dafür: Erstellen Sie einen Tablespace auf einem anderen Laufwerk mit viel zusätzlichem Speicherplatz und weisen Sie dann Ihre Problemtabelle diesem Tablespace zu. PostgreSQL kopiert die Tabelle in den neuen Tabellenbereich (wahrscheinlich sperrt sie die Tabelle dabei, sodass Sie ein Wartungsfenster benötigen). Dann VACFULL die Tabelle (löscht den größten Teil des alten Speicherplatzes, den die Tabelle im Standardtabellenbereich belegt). Dann CLUSTER den Tisch und es sollte sich verdichten. Setzen Sie es dann wieder in den Standardtabellenbereich und führen Sie VACFULL erneut aus (um den nicht verwendeten Speicherplatz im neuen Tabellenbereich zu löschen).

efesar
quelle
Am Ende habe ich die Tabelle neu erstellt (das Schema ausgegeben und daraus neu erstellt) und die Daten direkt aus einer der entfernten Datenbanken abgerufen. Nach Abschluss des Vorgangs war die Datenbank noch 35 GB groß, wobei nur 9 GB auf die "breite" Blob-Spalte entfielen. CLUSTERed, VACUUM FULLed, REINDEXed, und ich sitze immer noch auf einer Menge mysteriöser Festplattennutzung.
BrM13
Link ist tot :(
Hayd