mercoledì 6 ottobre 2010

Divagazioni sul table partitioning in PostgreSQL - parte 3

Torniamo per un momento al concetto originario di partizionamento di una tabella. E in particolare alla domanda ultima (non quella sulla vita, l'universo e tutto quanto): perché mai partizionare una tabella?
La risposta non è unica, come sempre. Personalmente ne vedo almeno 3:

  1. accelerare l'accesso ai dati quando questo non è completamente causale ma limitato ad alcuni sottoinsiemi della tabella originaria;
  2. semplificare lo "smaltimento" di gruppi di righe non più necessari alle operazioni correnti;
  3. allocare le singole partizioni su tablespace distinti (per accelerare l'accesso in modo più sottile).
Del primo caso abbiamo già detto. Eseguire una DROP TABLE su una tabella figlia, dopo averla esclusa dall'albero genealogico, è certamente più efficiente che una classica DELETE FROM ... WHERE, oltre al fatto che già la semplice esclusione dall'albero genealogico potrebbe essere sufficiente (ALTER TABLE ... NO INHERIT ...) ad un costo a dir poco ridicolo.
Quella dell'allocazione delle tabelle figlie su tablespace separati è una tecnica raffinata che richiede però uno studio comparativo attento fra i benefici derivanti dall'ottimizzazione sull' I/O rispetto al costo intrinseco derivante dalla gestione dell'albero genealogico. Su database molto "trafficati" in genere le ottimizzazioni sull' I/O dei dischi portano sempre a risultati significativi in positivo.
Tornando alla prima considerazione, va notato come in realtà la velocità dell'accesso dipende solo minimamente (ammesso che possa veramente dipendere) dalle dimensioni della tabella in sé. Una definizione oculata degli indici e delle query realmente in uso è la vera ricetta del successo. Del resto con dischi che stanno "sforando" la barriera del terabyte e con la gestione dei volumi logici, il problema di alloggiare tabelle enormi è diventato sempre meno sentito.
In sostanza, durante le query il planner (ovvero l'ottimizzatore) verifica se esistono uno o più indici, che di norma risiedono sui dischi, che possano tornare utili a recuperare le righe interessanti. In caso positivo cerca di caricare in memoria quelle porzioni di indici che possono servire per poi procedere al recupero effettivo delle righe.
Ciò porta quindi a pensare di partizionare gli indici piuttosto che le tabelle.
In questo modo rendo gli indici più piccoli e, se le query non "spazzolano" a caso sull'intera tabella, è probabile che alcuni di quei piccoli indici più utilizzati restino in cache, a tutto vantaggio della velocità.
Ovviamente PostgreSQL supporta nativamente questa tecnica tramite i cosiddetti "indici parziali". A questi è in sostanza associata un'espressione booleana che determina quali righe della tabella siano indicizzate. Si tratta di un'espressione che, ai nostri fini, ha le stesse finalità di quella della CHECK constraint usata nelle tecniche "ortodosse" illustrate in precedenza.
Chiaramente gli indici parziali, come anche le CHECK constraint, devono essere definite in modo che ogni riga della tabella possa "finire" in almeno uno degli indici parziali. Se è uno solo, tanto meglio.
Questa tecnica ha anche degli effetti collaterali benefici. Vediamone alcuni.

  1. Non serve un supporto in tempo reale (leggi "TRIGGER");
  2. Non serve un supporto "batch" per lo smistamento delle righe nelle tabelle figlie;
  3. Restando unica la tabella si può salvaguardare l'integrità referenziale.
Chiaramente c'è anche da pagare un qualche costo che è rappresentato dalla valutazione delle espressioni booleane associate agli indici ogni volta che il contenuto della tabella cambia (INSERT, UPDATE ecc.). Quindi, l'aggiornamento degli indici sarà intrinsecamente sempre più costoso.

E' chiaro, concludendo (o quasi) come non esista una ricetta unica e buona per tutti i palati. Del resto le condizioni a contorno della specifica applicazione (per non parlare degli specifici data set) cambiano da caso a caso. Lo scopo di queste divagazioni è quello di provare a guardare oltre lo status quo, sempre considerando i limiti, intrinseci e non, non solo delle tecniche ma anche di PostgreSQL.
Per i quali abbiamo dedicato le prossime divagazioni finali.

Nessun commento:

Posta un commento