martedì 21 novembre 2006

Streaming applicato ad un DBMS

Recentemente ho utilizzato i servizi database in due modalita':
- In un modello client/server, con client e server dispiegati su due macchine diverse
- In un modello tipo Java EE (oppure Unify, per quelli che sanno cosa voglio dire..) dove DBMS e application server risiedono sulla stessa macchina (o cluster), e interagiscono con un client (o un terminare remoto) trasferendo le informazioni "un po' alla volta, tante quante ce ne stanno a video"

Nel primo caso esiste un limite tale per cui il risultato di una query e' di dimensioni tali da saturare la rete, il client si blocca in attesa del completamento del trasferimento del result-set (e quindi l'utente e' scontento), il DBMS fa fatica a processare altre richieste (la rete e' satura!) ed il sistema processore + memoria + disco del DBMS non lavora in modo efficiente.
In questi casi, potrebbe essere conveniente utilizzare una tecnologia di tipo streaming, o meglio un modello produttore/consumatore per il trasferimento dei risultati della query: il db trasferisce i risultati al client "man mano che li trova", mentre il client rimane in una condizione non bloccante su un buffer, e "consuma" i record man mano che arrivano. Inoltre il server potrebbe lavorare tenendo conto del consumo di record da parte del client, cioe' in caso di buffer vuoto, dare la precedenza alla query, mentre in caso di buffer riempito, diminuire la priorita' del thread, lasciando piu' risorse a disposizione di altri utenti.Pero' utilizzando questo approccio si perde la possibilita' di ottenere un result-set ordinato dal DBMS, tranne che in pochi casi particolari. Immaginiamo un DBMS ad oggetti, e pensiamo di poter passare un comparatore alla query per determinarne l'ordinamento:

SELECT Cliente c ORDER USING new Comparator<Cliente>() {
   int compare( Cliente a, Cliente b )
   {
      return a.indirizzo.compare(b.indirizzo);
   }
};

Ora la streaming query potra' essere ordinata se e solo se esiste gia' un indice basato sul comparatore, e il DBMS e' in grado di utilizzare questo indice. In caso contrario, se l'ordinamento deve essere fatto “al volo”, il DBMS dovra' prima ottenere tutti i risultati della query e poi ordinarli utilizzando il comparatore. Ma come fa il DBMS a capire se due comparatori (quello nell'esempio e' costruito “al volo”) sono equivalenti, cioe' possono utilizzare gli stessi indici? Un metodo protrebbe essere quello di mantenere all'interno del DBMS le istanze dei comparatori utilizzati, ed implementare un metodo di confronto tra comparatori:

interface Comparator<T> extends Serializable
{
   int compare(T a, T b);
   bool isEquivalent(Comparator b);
   int hasCode();
}

Con comparatori di questo tipo, il DBMS potrebbe creare gli indici man mano che i comparatori vengono utilizzati (eventualmente con delle statistiche di utilizzo, ed una euristica di rimozione dei comparatori e relativi indici non utilizzati), naturalmente deve manutenere gli indici quando vengono modificati i dati, ma ha la possibilita' di effettuare delle comparazioni tra comparatori (l'iterazione e' umana, la ricorsione e' divina!) e decidere di utilizzare indici di ordinamento gia' esistenti. Naturalmente se l'indice richiesto non e' presente, deve venire creato, allungando ulteriormente il tempo di esecuzione della query. Potrebbe essere buono per un applicativo dove le query si ripetono, ma decisamente dannoso in un datawarehouse.

Nessun commento: