Crescita della tabella TOAST fuori controllo - FULLVAC non fa nulla


9

Di recente, ho avuto un server PostgreSQL 8.2.11 aggiornato a 8.4 per sfruttare le funzionalità di autovacuum ed essere in linea con altri 30 server PGSQL. Ciò è stato fatto da un gruppo IT separato che amministra l'hardware, quindi non abbiamo molta scelta su nessun altro aggiornamento (non vedremo 9+ per un po '). Il server esiste in un ambiente molto chiuso (rete isolata, privilegi di root limitati) e funziona su RHEL5.5 (i686). Dopo l'aggiornamento, il database è cresciuto costantemente fino a 5-6 GB al giorno. Normalmente, il database, nel suo insieme, è ~ 20 GB; attualmente è ~ 89 GB. Abbiamo un paio di altri server che eseguono database equivalenti e in realtà sincronizzano i record tra loro tramite un'applicazione di terze parti (uno che non ho accesso al funzionamento interno). Gli altri database sono ~ 20 GB come dovrebbero essere.

Eseguendo il seguente SQL, è abbastanza ovvio che c'è un problema con una tabella particolare e, più specificamente, con la sua tabella TOAST.

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;

Che produce:

              relazione | dimensione  
------------------------------------ + ---------  
  pg_toast.pg_toast_16874 | 89 GB  
  fews00.warmstates | 1095 MB  
  ...  
(20 righe)

Questa tabella TOAST è per una tabella chiamata "timeseries" che salva grandi record di dati BLOB. A SUM(LENGTH(blob)/1024./1024.)di tutti i record nella multiproprietà produce ~ 16 GB per quella colonna. Non ci dovrebbero essere motivi per cui la tabella TOAST di questa tabella dovrebbe essere così grande.

Ho eseguito un VACUUM FULL VERBOSE ANALYZE timeseriese il vuoto viene eseguito fino al completamento senza errori.

INFORMAZIONI: passare l'aspirapolvere "pg_toast.pg_toast_16874"
INFO: "pg_toast_16874": trovati 22483 rimovibili, 10475318 versioni di file non rimovibili in 10448587 pagine
DETTAGLIO: 0 versioni di file non ancora rimosse.
Le versioni di file non rimovibili vanno da 37 a 2036 byte.
Ci sono stati 20121422 puntatori oggetto inutilizzati.
Lo spazio libero totale (comprese le versioni di riga rimovibili) è di 0 byte. 4944885 pagine sono o diventeranno vuote, incluso 0 alla fine della tabella. 4944885 pagine contenenti 0 byte liberi sono potenziali destinazioni di spostamento.
CPU 75.31s / 29.59u sec trascorsi 877.79 sec.
INFORMAZIONI: l'indice "pg_toast_16874_index" ora contiene 10475318 versioni di riga in 179931 pagine
DETTAGLIO: 23884 versioni di riga di indice rimosse.
101623 pagine indice sono state eliminate, 101623 sono attualmente riutilizzabili.
CPU trascorsa 1,35 s / 2,46u sec 21,07 sec.

Indicizzato al tavolo che ha liberato un po 'di spazio (~ 1 GB). Non riesco a CLUSTER la tabella in quanto non c'è abbastanza spazio su disco per il processo e sto aspettando di ricostruire la tabella interamente poiché vorrei scoprire perché è molto più grande dei database equivalenti che abbiamo.

Ho eseguito una query dal wiki PostgreSQL qui - "Mostra database gonfio" , e questo è quello che ottengo:

database_attuale | schemaname | tablename | tbloat | wastedbytes | iname | ibloat | wastedibytes  
----------------- + ------------ + ------------------- ------------- + -------- + ------------- + ------------- -------------------- + -------- + --------------  
ptrdb04 | poche centinaia | multiproprietà | 1.0 | 0 | idx_timeseries_synchlevel | 0.0 | 0  
ptrdb04 | poche centinaia | multiproprietà | 1.0 | 0 | idx_timeseries_localavail | 0.0 | 0  
ptrdb04 | poche centinaia | multiproprietà | 1.0 | 0 | idx_timeseries_expirytime | 0.0 | 0  
ptrdb04 | poche centinaia | multiproprietà | 1.0 | 0 | idx_timeseries_expiry_null | 0.0 | 0  
ptrdb04 | poche centinaia | multiproprietà | 1.0 | 0 | uniq_localintid | 0.0 | 0  
ptrdb04 | poche centinaia | multiproprietà | 1.0 | 0 | pk_timeseries | 0.1 | 0  
ptrdb04 | poche centinaia | idx_timeseries_expiry_null | 0.6 | 0 | ? | 0.0 | 0

Sembra che il database non consideri questo spazio come "vuoto", ma non vedo da dove provenga tutto lo spazio su disco!

Ho il sospetto che questo server di database stia decidendo di utilizzare 4-5 volte lo spazio su disco per salvare gli stessi record estratti dagli altri server di dati. La mia domanda è questa: esiste un modo per verificare la dimensione del disco fisico di una riga? Vorrei confrontare le dimensioni di una riga su questo database con un altro database "integro".

Grazie per tutto l'aiuto che potete fornire!

AGGIORNAMENTO 1

Ho finito per ricostruire il tavolo da uno schema scaricato per le sue dimensioni (non potevo lasciarlo solo per un altro giorno). Dopo aver sincronizzato i dati, tramite il processo di sincronizzazione del software, la tabella TOAST era ~ 35 GB; tuttavia, potrei rappresentare solo ~ 9 GB da quella colonna BLOB che dovrebbe essere la più lunga in termini di valori. Non sono sicuro da dove provengano gli altri 26 GB. CLUSTER, VUOTO PIENO e REINDICATO inutilmente. I file postgresql.conf tra i server di dati locali e remoti sono esattamente gli stessi. C'è qualche motivo per cui questo database potrebbe tentare di archiviare ogni record con uno spazio maggiore su disco?

AGGIORNAMENTO 2 - Risolto

Alla fine ho deciso di ricostruire completamente il database da zero, arrivando persino a reinstallare i pacchetti PostgreSQL84 sul sistema. Il percorso del database è stato reinizializzato e i tablespace sono stati cancellati. Il processo di sincronizzazione del software di terze parti ha ripopolato le tabelle e la dimensione finale è risultata essere di ~ 12 GB ! Sfortunatamente, questo, in nessun modo, aiuta a risolvere qual era l'origine esatta del problema. Lo guarderò per un giorno o due e vedrò se ci sono differenze importanti nel modo in cui il database rivitalizzato sta gestendo la tabella TOAST e pubblicherò questi risultati qui.

Dimensione della relazione


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;

        relazione          |   dimensione   
 ------------------------- + --------- 
 pg_toast . pg_toast_17269 | 18 GB 
 poche centinaia . stati caldi        | 1224 MB
 ( 2 file )  

VACUUM VERBOSE ANALYZE timeseries;

INFO: "timeseries": trovate 12699 versioni rimovibili, 681961 non rimovibili in 58130 di 68382 pagine
DETTAGLIO: 0 versioni di righe morte non possono ancora essere rimosse.
C'erano 105847 puntatori oggetto inutilizzati.
0 pagine sono completamente vuote.
CPU 0.83s / 2.08u sec trascorsa 33.36 sec.
INFO: aspirapolvere "pg_toast.pg_toast_17269"
INFORMAZIONI: indice scansionato "pg_toast_17269_index" per rimuovere le versioni della riga 2055849
DETTAGLIO: CPU 0.37s / 2.92u sec trascorsi 13.29 sec.
INFO: "pg_toast_17269": rimosse 2055849 versioni di riga in 518543 pagine
DETTAGLIO: CPU 8.60s / 3.21u sec trascorsi 358.42 sec.
INFO: l'indice "pg_toast_17269_index" ora contiene 7346902 versioni di riga in 36786 pagine
DETTAGLIO: 2055849 versioni di riga dell'indice rimosse.
10410 pagine indice sono state eliminate, 5124 sono attualmente riutilizzabili.
CPU 0,00s / 0,00u sec. 0,01 sec.
INFORMAZIONI: "pg_toast_17269": trovati 1286128 rimovibili, 2993389 versioni di file non rimovibili in 1257871 su 2328079 pagine
DETTAGLIO: 0 versioni di righe morte non possono ancora essere rimosse.
C'erano 18847 puntatori oggetto inutilizzati.
0 pagine sono completamente vuote.
CPU 26.56s / 13.04u sec trascorsi 714.97 sec.
INFO: analisi di "fews00.timeseries"
INFO: "timeseries": scansionato 30000 di 68382 pagine, contenente 360192 righe attive e 0 righe morte; 30000 righe nel campione, 821022 righe totali stimate

L'unica differenza evidente dopo la ricostruzione (diversa dall'uso del disco) è

INFORMAZIONI: "pg_toast_17269": trovati 1286128 rimovibili, 2993389 versioni di file non rimovibili
come @CraigRinger menzionato in un commento. Il conteggio delle righe non rimovibili è molto più piccolo di prima.

Nuova domanda: altre tabelle possono influire sulla dimensione di un'altra tabella? (tramite chiavi esterne e simili) La ricostruzione della tabella non ha fatto nulla, ma la ricostruzione dell'intero database ha dimostrato di risolvere il problema.


Perché non hai eseguito l'aggiornamento direttamente alla 9.2? Ha ancora più miglioramenti nell'area del vaccino di 8,4 (e 8,4 andrà comunque in EOL il prossimo anno)
a_horse_with_no_name

Ho aggiornato il post. L'aggiornamento non è stato effettuato dal nostro negozio e non necessariamente dalla nostra richiesta. Sfortunatamente, non abbiamo questa opzione per eseguire l'aggiornamento a 9+.
BrM13

OK. Volevo solo assicurarmi di non trascurare l'ovvio;)
a_horse_with_no_name

Risposte:


9

Questo:

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

suggerisce che il problema di fondo è che qualcosa può ancora "vedere" quelle righe in modo che non possano essere rimosse.

I candidati per questo sono:

  • Transazioni preparate perse. Controllare pg_catalog.pg_prepared_xacts; dovrebbe essere vuoto. Anche correre SHOW max_prepared_transactions; dovrebbe riportare zero.

  • Sessioni di lunga durata con una transazione inattiva aperta. In PostgreSQL 8.4 e versioni successive questo dovrebbe essere solo un problema per le SERIALIZABLEtransazioni. Controllare pg_catalog.pg_stat_activityper <IDLE> in transactionle sessioni.

Molto probabilmente hai un client che non riesce a eseguire il commit o il rollback delle transazioni durante lunghi periodi di inattività.

Se questo non risulta essere, la prossima cosa che controllerei sarebbe quella di fare una somma octet_sizedi ciascuna colonna della tabella di interesse. Confrontalo con quello pg_relation_sizedel tavolo e del suo TOASTtavolino. Se c'è una grande differenza, probabilmente lo spazio consumato non è più visibile e probabilmente hai problemi di gonfiaggio della tabella. Se sono abbastanza simili, puoi iniziare a restringere dove si trova lo spazio riassumendo le dimensioni degli ottetti per colonna, ottenendo i primi valori 'n', ecc.


1) pg_prepared_xacts e max_prepared_transactions sono effettivamente tornati vuoti. 2) Esistono sicuramente alcune transazioni IDLE dalle SELECT * FROM pg_stat_activity WHERE current_query LIKE '<IDLE>%';quali si ottengono circa 30-40 risultati; tuttavia, questo sembra abbastanza normale. Ho controllato alcuni server "sani", ed erano uguali.
BrM13

3) Ecco cosa ho fatto. Passato attraverso le colonne della serie temporale, tirando octet_length (colonna). Moltiplicato ogni valore per il conteggio delle righe e sommato. Per il timeseries, ho ricevuto ~ 430 MB (vicino ai 493 MB da pg_relation_size) e 438 MB per la tabella TOAST (usando le colonne chunk_id, chunk_seq, chunk_data). Le stime sembrano corrette e la tabella TOAST è MODALMENTE al largo della relazione_dimensione di circa 2 ordini di grandezza (60 GB oggi). Sembra che io abbia il gonfiore, ma non il tipo tradizionale (gonfiore inutilizzato). Altrimenti, un FULLVAC dovrebbe occuparsi del problema.
BrM13

@Brad Le sessioni inattive vanno bene, sono solo le sessioni inattive con transazioni aperte che rappresentano un problema, vale a dire <IDLE> in transaction, e solo se sono state (a) inattive per un po 'e (b) stanno usando l' SERIALIZABLEisolamento o sei su 8.3 o più vecchio.
Craig Ringer

@Brad È interessante notare che solo la TOASTtabella sembra gonfia. A proposito, se hai usato VACUUM FULLmolto su un server precedente alla 9.0, ti consigliamo di farlo REINDEXcome VACUUM FULLsu quelle versioni potrebbe causare un notevole gonfiamento dell'indice. Ora mi chiedo se qualcuno abbia messo un assurdo FILLFACTORsul tavolo dei toast, anche se questo non dovrebbe farti superare il consumo di spazio 10 volte.
Craig Ringer

Grazie per il chiarimento IDLE. Ho pensato che fosse quello che volevi dire, ma è bene saperlo con certezza. Per quanto riguarda FILLFACTOR, la tabella utilizza l'impostazione predefinita. Cordiali saluti - Secondo la documentazione 8.4 CREATE TABLE il valore predefinito è 100 e non è possibile impostare un FILLFACTOR per la tabella TOAST.
BrM13

0

Non ho idea del perché sia ​​gonfio. Ma ho fatto qualche ricerca e forse questo link ha qualche intuizione: http://postgresql.1045698.n5.nabble.com/A-154-GB-table-swelled-to-527-GB-on-the-Slony-slave -Come compattare-it-td5543034.html ... Non è la tua situazione esatta, ma forse è abbastanza vicino da aiutarti a raggiungere il fondo del fantasma gonfio.

Tuttavia, penso che l'unico modo per compattare quella tabella a questo punto sia CLUSTER. Dato che hai poco spazio su disco, questo è un problema.

Ecco il mio suggerimento: crea un tablespace su un'unità diversa con molto spazio extra, quindi assegna la tabella dei problemi a tale tablespace. PostgreSQL copierà la tabella nel nuovo tablespace (probabilmente lo bloccherà nel processo, quindi avrai bisogno di una finestra di manutenzione). Quindi VACFULL la tabella (cancella la maggior parte dello spazio vecchio consumato dalla tabella nel tablespace predefinito). Quindi CLUSTER il tavolo e dovrebbe compattarsi. Quindi reinserirlo nel tablespace predefinito ed eseguire nuovamente VACFULL (per cancellare lo spazio inutilizzato nel nuovo tablespace).


In realtà ho finito per ricostruire la tabella (scaricando lo schema e ricostruendo da quello) e estraendo i dati direttamente da uno dei database remoti. Al termine del processo, il database era ancora 35 GB con solo 9 GB rappresentati dalla colonna BLOB "ampia". CLUSTER, VUOTO PIENO, REINDICATO, e sono ancora seduto su un sacco di misterioso utilizzo del disco.
BrM13

Il link è morto :(
hayd
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.