2001/02 Lezione N. 16 Organizzazione di banche dati Meccanismi di indicizzazione e strutture dati. I meccanismi di indicizzazione e le strutture dati utilizzate per la rappresentazione delle tabelle e degli indici determinano le prestazioni del database, che si misurano in base ai tempi di inserimento, modifica, cancellazione e consultazione (nel caso migliore, medio e peggiore). Tali tempi sono espressi come prodotto del numero di accessi necessari ad ultimare l’operazione per il tempo di accesso unitario (considerato costante per tutti i record). In genere, il numero di accessi dipende dal numero di record nella tabella (N) e dalle dimensioni della struttura dati dell’indice. Altra caratteristica importante è l’eventuale necessità di riordinare periodicamente i dati archiviati. Nel seguito non considereremo i tempi di modifica di un record, osservando che la modifica comporta una ricerca preventiva del record, alla cui complessità occorre aggiungere il tempo effettivo di modifica. Per valutare quest’ultimo occorre distinguere due casi: se la modifica non coinvolge i campi chiave, il tempo è unitario (o costante); se la modifica coinvolge i campi chiave può essere necessaria una riorganizzazione dell’indice la cui complessità è la somma delle complessità di una cancellazione e di una inserzione. Tabelle non ordinate. Non necessitano di alcun indice, né di alcuna riorganizzazione. Il tempo di inserimento di un record è unitario, mentre la modalità di ricerca è sequenziale. Pertanto il tempo di consultazione è 1 nel caso migliore, N nel caso peggiore, N/2 in media. I tempi di cancellazione e modifica sono dominati dal tempo di ricerca. Ogni tabella è fisicamente ordinata in base all’indice relativo di inserimento, che ne costituisce una chiave primaria. Se la chiave di ricerca è l’indice relativo la consultazione avviene per accesso diretto del record associato alla riga prescelta della tabella. Il tempo di consultazione diviene quindi unitario, come quello di aggiornamento. Il vantaggio principale delle tabelle non ordinate è la semplicità. Lo svantaggio principale è il tempo di consultazione elevato, o il vincolo ad utilizzare l’indice relativo come chiave per effettuare ricerche efficienti. Tabelle con indici. L’uso di indici consente di superare i limiti delle tabelle non ordinate. Infatti, creando un indice ordinato in base ad un campo chiave di una tabella si possono effettuare ricerche ordinate sulla tabella senza modificarne direttamente la rappresentazione. Inoltre, per una stessa tabella possono essere creati indici ordinati in base a chiavi diverse, consentendo quindi di effettuare ricerche efficienti secondo diversi criteri. Gli indici possono essere ordinati fisicamente o logicamente. Nel primo caso gli elementi dell’indice possono essere visti a loro volta come le righe di una tabella la cui posizione fisica rappresenta l’ordine. Nel secondo caso gli elementi dell’indice sono fisicamente disposti come i record (non ordinati) della tabella a cui puntano, ma sistemi di puntatori creano un ordine logico diverso da quello fisico. Ordinamento fisico Indici ordinati fisicamente. Se l’indice è ordinato fisicamente in base ad una chiave della tabella, la ricerca (secondo tale chiave) può avvenire in modo sequenziale (con le stesse prestazioni indicate per le tabelle non ordinate) o dicotomico. La ricerca dicotomica ad ogni accesso dimezza il numero di record su cui continuare la ricerca. Il tempo di consultazione nel caso peggiore si riduce così a log2(N+1), quello medio a log2(N+1)-1 (approssimati per eccesso all’intero più vicino). Lo svantaggio principale dell’ordinamento fisico è che per ogni nuovo inserimento occorre riordinare l’indice (cioè inserire il nuovo elemento dell’indice nella posizione giusta). Questo comporta, per ogni nuovo inserimento, una ricerca e lo spostamento di tutti gli elementi dell’indice in posizioni successive a quella di inserimento (N/2 in media), per una complessità totale media di log2(N)+N/2. Per ovviare a questa inefficienza si può utilizzare un indice provvisorio disordinato per i record di recente inserzione, effettuando riordinamenti periodici dell’intero indice. Ordinamento logico Indici ordinati logicamente: lista ordinata. Ogni elemento dell’indice contiene un campo che punta all’indirizzo relativo dell’elemento che segue nell’ordinamento logico. L’ordine logico non richiede riorganizzazioni per essere mantenuto a seguito di un nuovo inserimento. Individuata la posizione del record da inserire, è sufficiente aggiornare i puntatori dell’elemento precedente e dell’elemento stesso (operazioni di complessità costante). Considerazioni analoghe valgono per la cancellazione di un record. Lo svantaggio è che la ricerca può essere effettuata solo in modo sequenziale, seguendo la lista ordinata a partire da un puntatore al primo elemento. Le liste ordinate sono però notevolmente più efficienti delle tabelle non ordinate nel caso di accessi multipli finalizzati, ad esempio, alla stampa in ordine di tutti i record del database (Es: stampa di un elenco telefonico secondo l’ordine alfabetico degli abbonati). In caso di tabelle non ordinate questo comporterebbe N accessi sequenziali di 2 complessità media N/2 ciascuno (tempo complessivo N /2) in caso di liste ordinate l’operazione richiede solo la scansione dell’indice (tempo complessivo N). Indici ordinati logicamente: albero binario. Un albero binario è un albero i cui rami si biforcano ripetutamente dalla radice fino alle foglie. Ogni elemento dell’indice è un nodo dell’albero, cioè un punto di biforcazione o una foglia. Ad ogni elemento sono associati due puntatori (campi) che puntano agli indirizzi relativi di altri due nodi (detti figli). Il nodo radice non è puntato da nessun altro nodo, i nodi foglia non puntano a nessun altro nodo. Tutti i restanti nodi puntano ad uno o due nodi figli e sono puntati da un solo nodo padre. Chiamiamo destro e sinistro i due figli di uno stesso nodo. Perché l’albero binario rappresenti un ordinamento logico (crescente) occorre che siano soddisfatte le seguenti condizioni: ogni figlio destro deve avere la chiave più grande (cioè successiva nell’ordinamento) di quella del rispettivo nodo padre; ogni figlio sinistro deve avere la chiave più piccola (cioè precedente nell’ordinamento) di quella del rispettivo nodo padre. La profondità di un albero binario bilanciato è log2(N). Gli alberi binari si prestano ad effettuare ricerche dicotomiche a partire dalla radice. Il tempo di consultazione è 1 nel caso migliore (il nodo cercato è la radice), log2(N) nel caso peggiore (il nodo cercato è una foglia), log2(N)-1 nel caso medio. L’inserimento crea sempre una nuova foglia, e comporta una ricerca binaria di complessità logaritmica. Meritano attenzione gli algoritmi di cancellazione di un record (complessità logaritmica) e di stampa ordinata di tutti i record (complessità lineare). Si veda Boni, pag. 420 e seguenti. Ref: Boni Cap. 7.407-430