lunedì 11 ottobre 2010

Divagazioni sul table partitioning in PostgreSQL - parte 4

Affinché tutto quanto abbiamo detto finora abbia un senso nel mondo reale c'è bisogno che PostgreSQL sia in grado di gestire i vari meccanismi sottostanti in modo efficiente. Vediamo il perché.
Nel caso si utilizzi l'ereditarietà è importante che il planner sappia scegliere in modo efficiente quali tabelle figlie effettivamente interrogare. In questo caso definirei "efficiente" un algoritmo a complessità sub-lineare, cioè il cui tempo di esecuzione cresce meno che una funzione lineare. E' il caso tipico della ricerca dicotomica che impiega tempi logaritmici rispetto al numero di elementi dell'insieme.
Lo stesso ragionamento vale per la tecnica che sfrutta il partizionamento degli indici, dove la ricerca si sposta dalle tabelle della gerarchia alla lista degli indici della tabella unica.
Questo perché se il numero di partizioni aumenta (e di norma lo fa col tempo), non vorremmo che aumentasse (troppo) il tempo che il planner impiega a capire quali tabelle figlie (o indici parziali) scartare e quali no.
Con un insieme 100 volte più grande quella ricerca dovrebbe richiede al massimo poche iterazioni in più per essere completata, come nella ricerca dicotomica.
E PostgreSQL?
Stando a quanto riportato nelle mailing list ufficiali da sviluppatori di prima linea del progetto, una gerarchia con più di una dozzina di tabelle figlie è considerata non praticabile. E, per quanto se ne sa, nessuno ha mai preso in considerazione gerarchie con più di un livello!
Le stesse considerazioni portano alle stesse conclusioni in merito al numero di indici parziali.
Questo perché, non solo a mio sentire, nei meandri più nascosti del planner si annidano algoritmi (o loro implementazioni) che non solo non sono sub-lineari ma, questo è il pericolo, sono addirittura super-lineari (che crescono cioè come i polinomi e oltre).
Cosa fare dunque? Le possiblità non sono molte.

  1. Rinunciare al partizionamento "automatico" e fare in modo che l'applicazione sappia scegliere da sé quali tabelle effettivamente interrogare.
  2. Rinunciare al partizionamento tout-court e affidarsi a grandi quantità di memoria per tenere in cache quanta più parte è possibile delle tabelle in questione e relativi indici;
  3. Rimboccarsi le maniche e mettere mano al codice del planner;
  4. Provare a rientrare nei limiti di una dozzina o poco più di tabelle figlie (o indici parziali).
Mi sembra che al momento (sfidanti, fatevi avanti!) sia le funzioni di ereditarietà che quelle di indicizzazione parziale siano più dei "segnaposto" accademici (per dire "ce l'ho") che delle caratteristiche utili nel mondo reale. Limitazioni che stanno ben dentro al primo ordine di grandezza tengono certamente lontano un progetto come PostgreSQL dal mondo enterprise, dove i numeri girano per miliardi come unità di misura.
La mia non vuole essere una feroce critica a quello che ritengo veramente essere il più avanzato RDBMS opensource esistente. Vorrebbe essere piuttosto uno sprone alla comunità per una revisione di quelle parti che, per dirla in termini tecnici, "non scalano bene" parallelamente a tutte le altre interessanti attività di cui si sta già occupando per la prossima versione 9.1.

Concludo con un parallelo. Il kernel di Linux ha cominciato a prendere piede nei territori dell' "enterprise grade" (a misura di impresa industriale) anche grazie alla riprogettazione dello scheduler che altrimenti aveva complessità lineare: più processi da gestire = più tempo necessario per gestirli. Ora quel costo è praticamente indipendente  non solo dal numero di processi, ma anche di processori. Aggiungere feature chiaramente non basta.

Nessun commento:

Posta un commento