2012-12-18 14 views
7

Abbiamo un prodotto che utilizza il server di database PostgreSQL distribuito in un paio di centinaia di client. Alcuni di questi hanno raccolto decine di gigabyte di dati nel corso degli anni. Quindi nella prossima versione introdurremo procedure di pulizia automatica che archivieranno gradualmente e vecchi record DELETE durante i processi batch notturni.PostgresQL Automazione di VACUUM FULL per tavoli gonfiati

Se ho capito correttamente, autovacuum eseguirà l'avvio e analizzerà e riorganizzerà le tuple, quindi le prestazioni saranno come quando esistevano meno record.

Lo spazio disco effettivo non sarà rilasciato, se comprendo correttamente, poiché questo si verifica solo con un VACUUM FULL, e che non è attivato da autovacuum.

Quindi stavo pensando a un processo automatizzato che lo avrebbe fatto.

Ho trovato la vista ingrandita che viene utilizzata da nagios check_postgres a http://wiki.postgresql.org/wiki/Show_database_bloat.

Questa visualizzazione è valida? Ho ragione nel capire che se il tbloat è> 2, potrebbe usare un VACUUM PIENO? E se il ibloat è troppo alto, potrebbe utilizzare un REINDEX?

Eventuali commenti sul seguente lavoro da eseguire come lavoro batch giornaliero?

  • vacuumdb -Z mydatabase #vacuum con analizzare solo
  • select tablename from bloatview order by tbloat desc limit 1
  • vacuumdb -f -t tablename mydatabase
  • select tablename, iname from bloatview order by ibloat desc limit 1
  • reindexdb -t tablename -i iname mydatabase

Fuori rotta, ho ancora bisogno di avvolgerlo in un bel script perl in crontab (stiamo usando Ubuntu 12), o Postgresql ha qualche tipo di scheduler potrei farlo?

O è questo totale eccessivo e c'è una procedura molto più semplice?

+0

vacuumdb -Z probabilmente non è necessario, l'autovacuum sembra fare un ottimo lavoro per mantenere l'analisi aggiornata. – greyfairer

risposta

4

Probabilmente don' ne ho bisogno È bene farlo una volta - dopo la prima archiviazione del lavoro in modo da recuperare lo spazio sul disco, ma in seguito il lavoro di archiviazione quotidiano e l'autovacuum impediranno alle bolle morte di gonfiarsi.

Inoltre, anziché vacuum full, è spesso preferibile eseguire cluster table_name using index_name; analyze table_name.Questo riordina le righe in base a un indice. In questo modo le righe della tabella correlate possono essere salvate fisicamente vicino al disco, il che può limitare la ricerca del disco (importante sulle unità disco classiche, in gran parte irrilevante su SSD) e un numero di letture per le query tipiche.

E ricorda che sia vacuum full e cluster renderanno inutilizzabili le tue tabelle durante l'esecuzione.

+0

Grazie per il suggerimento. Il processo di pulizia che abbiamo introdotto sarà programmato per funzionare per un paio d'ore durante la notte, ma ci vorranno diverse notti in alcuni clienti prima che sia finito. Sono d'accordo che è meglio aspettare fino al completamento della pulizia, quindi eseguire il vuoto completo o il cluster solo una volta durante un periodo di inattività pianificato. Solo abbiamo 200 installazioni, per cui dobbiamo programmarlo, ecco perché vogliamo un'automazione per questo. Grazie per il suggerimento su CLUSTER. – greyfairer

+0

Da Postgresql 9.0 e successive ottimizzazioni su 'VACUUM FULL' lo ha reso il modo corretto per farlo. (vedi: https://wiki.postgresql.org/wiki/VACUUM_FULL#CLUSTER) –

3

OK, ci ho lavorato.

ho semplificato/rielaborata al fine di dividerlo in due seguenti:

CREATE OR REPLACE VIEW 
    bloat_datawidth AS 
SELECT 
    ns.nspname AS schemaname, 
    tbl.oid AS relid, 
    tbl.relname, 
    CASE 
     WHEN every(avg_width IS NOT NULL) 
     THEN SUM((1-null_frac)*avg_width) + MAX(null_frac) * 24 
     ELSE NULL 
    END AS datawidth 
FROM 
    pg_attribute att 
JOIN 
    pg_class tbl 
ON 
    att.attrelid = tbl.oid 
JOIN 
    pg_namespace ns 
ON 
    ns.oid = tbl.relnamespace 
LEFT JOIN 
    pg_stats s 
ON 
    s.schemaname=ns.nspname 
AND s.tablename = tbl.relname 
AND s.inherited=false 
AND s.attname=att.attname 
WHERE 
    att.attnum > 0 
AND tbl.relkind='r' 
GROUP BY 
    1,2,3; 

E

CREATE OR REPLACE VIEW 
    bloat_tables AS 
SELECT 
    bdw.schemaname, 
    bdw.relname, 
    bdw.datawidth, 
    cc.reltuples::bigint, 
    cc.relpages::bigint, 
    ceil(cc.reltuples*bdw.datawidth/current_setting('block_size')::NUMERIC)::bigint AS expectedpages, 
    100 - (cc.reltuples*100*bdw.datawidth)/(current_setting('block_size')::NUMERIC*cc.relpages) AS bloatpct 
FROM 
    bloat_datawidth bdw 
JOIN 
    pg_class cc 
ON 
    cc.oid = bdw.relid 
AND cc.relpages > 1 
AND bdw.datawidth IS NOT NULL; 

E il processo di cron:

#!/bin/bash 

MIN_BLOAT=65 
MIN_WASTED_PAGES=100 
LOG_FILE=/var/log/postgresql/bloat.log 
DATABASE=unity-stationmaster 
SCHEMA=public 

if [[ "$(id -un)" != "postgres" ]] 
then 
echo "You need to be user postgres to run this script." 
exit 1 
fi 

TABLENAME=`psql $DATABASE -t -A -c "select relname from bloat_tables where bloatpct > $MIN_BLOAT and relpages-expectedpages > $MIN_WASTED_PAGES and schemaname ='$SCHEMA' order by wastedpages desc limit 1"` 

if [[ -z "$TABLENAME" ]] 
then 
echo "No bloated tables." >> $LOG_FILE 
exit 0 
fi 

vacuumdb -v -f -t $TABLENAME $DATABASE >> $LOG_FILE