Dimensione database iniziale PostgreSQL


12

Ci sono 2 parti alla mia domanda.

  1. Esiste un modo per specificare la dimensione iniziale di un database in PostgreSQL?
  2. In caso contrario, come gestisci la frammentazione quando il database cresce nel tempo?

Di recente sono migrato da MSSQL a Postgres e una delle cose che abbiamo fatto nel mondo MSSQL durante la creazione di un database è stata quella di specificare la dimensione iniziale del database e del registro delle transazioni. Ciò ha ridotto la frammentazione e aumentato le prestazioni, soprattutto se si conosce in anticipo la dimensione "normale" del database.

Le prestazioni del mio database diminuiscono con l'aumentare delle dimensioni. Ad esempio, il carico di lavoro che sto attraversando richiede normalmente 10 minuti. Man mano che il database cresce, questa volta aumenta. Fare un VUOTO, VUOTO PIENO e VUOTO PIENO ANALISI non sembra risolvere il problema. Ciò che risolve il problema delle prestazioni è l'arresto del database, la frammentazione del disco e quindi l'esecuzione di un ANALIZZO COMPLETO VACUUM riporta le prestazioni del mio test ai 10 minuti originali. Questo mi porta a sospettare che la frammentazione sia ciò che mi sta causando dolore.

Non sono stato in grado di trovare alcun riferimento alla prenotazione di tablespace / spazio del database in Postgres. O sto usando una terminologia sbagliata e quindi non trovo nulla, oppure esiste un modo diverso di mitigare la frammentazione del filesystem in Postgres.

Qualche puntatore?

La soluzione

Le risposte fornite mi hanno aiutato a confermare ciò che avevo iniziato a sospettare. PostgreSQL memorizza il database su più file e questo è ciò che consente al database di crescere senza preoccuparsi della frammentazione. Il comportamento predefinito è comprimere questi file fino all'orlo con i dati della tabella, il che è utile per le tabelle che cambiano raramente, ma è dannoso per le tabelle che vengono aggiornate frequentemente.

PostgreSQL utilizza MVCC per fornire accesso simultaneo ai dati della tabella. In base a questo schema, ogni aggiornamento crea una nuova versione della riga che è stata aggiornata (potrebbe essere tramite timestamp o numero di versione, chi lo sa?). I vecchi dati non vengono immediatamente eliminati, ma contrassegnati per l'eliminazione. La cancellazione effettiva si verifica quando viene eseguita un'operazione VACUUM.

Come si collega questo al fattore di riempimento? Il fattore di riempimento predefinito di 100 della tabella comprime completamente le pagine della tabella, il che a sua volta significa che non vi è spazio all'interno della pagina della tabella per contenere le righe aggiornate, ovvero le righe aggiornate verranno posizionate in una pagina della tabella diversa dalla riga originale. Questo è negativo per le prestazioni, come dimostra la mia esperienza. Poiché le mie tabelle di riepilogo vengono aggiornate molto frequentemente (fino a 1500 righe / sec), ho scelto di impostare un fattore di riempimento di 20, ovvero il 20% della tabella sarà per i dati delle righe inseriti e l'80% per i dati di aggiornamento. Sebbene ciò possa sembrare eccessivo, la grande quantità di spazio riservato alle righe aggiornate significa che le righe aggiornate rimangono nella stessa pagina dell'originale e c'è una pagina della tabella non piena quando il daemon autovacuum viene eseguito per rimuovere le righe obsolete.

Per "riparare" il mio database, ho fatto quanto segue.

  1. Imposta il fattore di riempimento delle mie tabelle di riepilogo su 20. Puoi farlo al momento della creazione passando un parametro su CREATE TABLE o dopo il fatto tramite ALTER TABLE. Ho emesso il seguente comando plpgsql:ALTER TABLE "my_summary_table" SET (fillfactor = 20);
  2. Emesso un VACUUM FULL, in quanto questo scrive una versione completamente nuova del file della tabella e quindi, implicitamente, scrive un nuovo file della tabella con il nuovo fattore di riempimento .

Rieseguendo i miei test, non vedo alcun peggioramento delle prestazioni anche quando il database è grande quanto ho bisogno che lo sia con molti milioni di righe.

TL; DR - La frammentazione dei file non era la causa, era la frammentazione del tablespace. Ciò viene mitigato modificando il fattore di riempimento della tabella per adattarlo al proprio caso d'uso.


Dubito che sia l'operazione di ridimensionamento dei file. La mia ipotesi è che il mantenimento degli indici sia ciò che rallenta gli inserti. C'è una discussione in corso sulla mailing list di PG in merito (anche se senza soluzione): postgresql.1045698.n5.nabble.com/…
a_horse_with_no_name

Risposte:


4
  1. Non l'unica cosa vicina a ciò è quando si compila il server con l'opzione --with-segsize, questo potrebbe aiutare se la tabella occupa più spazio di un concerto e il file system può gestire un singolo file che si trova su un concerto. Se si inseriscono 20 concerti, sarà necessario creare 20 file se non si utilizza questa opzione. Se il tuo file system è in grado di gestire un file nel corso di un concerto, puoi semplicemente impostarlo su un valore elevato, molto probabilmente vedrai qualche vantaggio, nel peggiore dei casi un piccolo vantaggio.

  2. Dai un'occhiata a CLUSTER http://www.postgresql.org/docs/9.1/static/sql-cluster.html e FILLFACTOR http://www.postgresql.org/docs/9.1/static/sql-createtable.html , http://www.postgresql.org/docs/9.1/static/sql-createindex.html

Si noti che FILLFACTOR può essere applicato a tabelle e indici.


5

C'è un'altra cosa in gioco che non ha ancora inserito le tue equazioni: aggiornamento CALDO . Risposte correlate:

Impostazione FILLFACTORa partire da 20 non sembrare eccessivo. Gonfia il tavolo fino a cinque volte le sue dimensioni. Se gli aggiornamenti HOT funzionano, non dovresti andare così in basso - normalmente .

Ci sono eccezioni: gli aggiornamenti HOT possono riutilizzare solo tuple morte da transazioni precedenti , non da quelle uguali o simultanee . Pertanto, un carico simultaneo pesante o transazioni lunghe che aggiornano ripetutamente le stesse righe possono giustificare un'impostazione così bassa (o persino inferiore).

Se hai grandi aggiornamenti, cambiando grandi parti della tabella in una sola volta, potresti voler dividerli in un paio di blocchi, idealmente cambiando solo quante righe contemporaneamente adattandole localmente nella pagina dei dati. Ma è difficile stimare e regolare.

Si noti che gli aggiornamenti HOT funzionano solo quando le colonne modificate non sono coinvolte in alcun modo negli indici (né come dati né come condizioni in un indice parziale). Potresti bloccare gli aggiornamenti HOT con indici su colonne aggiornate. Se quelli sono sacrificabili, è possibile ottenere prestazioni complessive migliori senza di essi.

Infine, puoi impostare i parametri di autovacuum per tabella . Potresti scegliere come target tabelle fortemente aggiornate con impostazioni aggressive che consentono un impacchettamento di righe un po 'più stretto che solo FILLFACTOR 20.


1
Roba interessante, ne avrò una lettura e cercherò di capire meglio cosa significano gli aggiornamenti HOT per il mio sistema.
CadentOrange,

4

Se il tuo problema è la frammentazione dei file, allora no, non lo è. In Postgres ogni tabella ottiene il proprio file o set di file se utilizza TOAST nel file system. Ciò differisce, per esempio, da Oracle (o apparentemente MS-SQL) in cui si creano file tablespace pre-dimensionati in cui inserire le tabelle, anche se anche lì si potrebbero avere problemi di frammentazione del file system se i file del tablespace vengono estesi o il file system è tanto male frammentato per cominciare.

Quanto alla tua seconda domanda ... Non ho idea di come gestire in modo chiaro la frammentazione del file system poiché MS-Windows è l'unico sistema operativo in cui ho riscontrato problemi di frammentazione e non eseguo MS-Windows più che assolutamente deve essere in questi giorni. Forse posizionare i file del database sui propri dischi potrebbe mitigarlo in una certa misura.


Tieni presente che hai una frammentazione interna del database PostgreSQL e una frammentazione del file system esterno. Interno credo che possa essere mitigato con VUOTO e usando CLUSTER e FILLFACTOR. Il file system può essere gestito eseguendo una deframmentazione per il file system specificato. E i file system Linux / Unix possono essere frammentati alcune volte a seconda del carico di lavoro e del tipo di file system.
Kuberchaun,

La frammentazione del file system non è attualmente un grosso problema con NTFS.
a_horse_with_no_name

1
Pensavo che NTFS fosse famoso per questo? La macchina della mia stazione di lavoro viene danneggiata abbastanza bene, l'unica cosa che la tiene sotto controllo è una deframmentazione pianificata che Windows7 esegue quotidianamente.
Kuberchaun,
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.