La risposta non è unica, come sempre. Personalmente ne vedo almeno 3:
- accelerare l'accesso ai dati quando questo non è completamente causale ma limitato ad alcuni sottoinsiemi della tabella originaria;
- semplificare lo "smaltimento" di gruppi di righe non più necessari alle operazioni correnti;
- allocare le singole partizioni su tablespace distinti (per accelerare l'accesso in modo più sottile).
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.
- Non serve un supporto in tempo reale (leggi "TRIGGER");
- Non serve un supporto "batch" per lo smistamento delle righe nelle tabelle figlie;
- Restando unica la tabella si può salvaguardare l'integrità referenziale.
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