• Heap file • File ordinati • Indici o Hash o B+-tree • Costo delle operazioni algebriche Simboli: • • • • NP: numero di pagine NR: numero record LP: lunghezza pagina LR: lunghezza record Memorizzazione di una relazione Heap: file non ordinati. • • • • Occupazione memoria: NP = (NR*LR)/LP Costo ricerca per chiave = NP/2 oppure NP (se la chiave è presente o no) Costo ricerca per intervallo: σ( k1 <= k <= k2) (R) = NP Ricerca con selezione di uguaglianza: σ( A=a) (R) = NP Esempio: Si consideri una relazione di NR=30.000 tuple, ognuna di lunghezza LR=100 byte, memorizzate su pagine di lunghezza LP=1024 byte. Le tuple sono indivisibili. Pertanto, il numero di pagine necessario è pari a NP=30000*100/1024 = 3000. Una qualsiasi ricerca quindi costa C= 3000 (1500 in media nel caso di ricerca per chiave). File ordinato • • • • • Occupazione memoria: NP = (NR*LR)/LP Costo ricerca sequenziale (per chiave) = NP/2 (caso medio) Costo ricerca binaria (per chiave) = log(NP) (caso peggiore)1 Costo ricerca per intervallo (k1 <= k <= k2), dove K è la chiave di ordinamento: σ( k1 <= k <= k2) (R) = log(NP) + f * NP - 1, dove f = (k1-k2)/(kmax-kmin) Ricerca con selezione di uguaglianza: σ( A=a) = log(NP) + f * NP - 1, dove f è la frazione di record che soddisfano il predicato di selezione Esempio: Una ricerca binaria costa log2(3000) = 12 accessi a pagine. Siano Kmax=10.000, Kmin=1000, K1=300, K2=500. Il costo della ricerca per intervallo è 12+0,02*3000= 72 pagine 1 Deve essere supportato l’accesso diretto alle pagine; ciò richiede che siano memorizzate sequenzialmente 1 INDICI Definizioni: Un indice è una struttura dati (ausiliaria) che velocizza le ricerche per chiave (di ricerca). Esso può essere calcolato (funzioni hash) o tabellato. In quest’ultimo caso, esso è un insieme di coppie (k,p), dove k è un valore della chiave e p è il puntatore alla pagina che contiene il record (o i record) con chiave k. Un indice può essere: • primario: l’attributo di indicizzazione è chiave (o superchiave) • secondario: l’attributo di indicizzazione non contiene una chiave (quindi, in generale, ammette duplicati) • clustered: la relazione è ordinata rispetto all’attributo di indicizzazione. Indice calcolato - FUNZIONE HASH (statico) È una tecnica di ricerca e/o memorizzazione L’indice può essere primario o secondario Se usato anche per memorizzare allora è clustered h(k) = k mod n, dove • • k: codifica numerica della chiave n: numero di pagine del file h(k) = k mod n = ultimi logn bit di k (se n è una potenza di 2) Problema sinonimi: più chiavi vengono assegnate alla stessa pagina – gestione dell’overflow Indice Tabellato – B+-tree Un B+-tree di ordine m ≥3 è un albero (ad m vie) 1. 2. 3. 4. 5. 6. bilanciato (le foglie sono tutte allo stesso livello) L’ordine m è il numero max di figli (puntatori) di ogni nodo non foglia; ogni nodo non foglia, tranne la radice, ha almeno m/2 figli se un nodo non foglia ha j valori della chiave, ha j+1 figli i valori all’interno di un nodo sono ordinati ogni foglia ha almeno m/2 coppie (valore, puntatore al record), un puntatore alla foglia successiva ed uno a quella precedente; tali coppie sono ordinate 7. Ogni chiave appare in una foglia 8. Ogni nodo è memorizzato in una pagina ESEMPIO. Si supponga che l’attributo di indicizzazione sia lungo 9 byte e che il puntatore alle pagine sia lungo 6 byte. Se m è l’ordine dell’albero, ogni nodo interno può contenere al massimo (m-1)*9 chiavi e m*6 puntatori. Nell’ipotesi che una pagina sia lunga 512 byte (m-1)*9 + m*6 <= 512 15 m <= 521 m= 34 Se ogni nodo non foglia ha m figli e l’altezza è h, allora ci sono mh-1 nodi foglia. Nella pratica, il valore medio di figli è F minore di m (70%). Se F=100, allora un albero di altezza 4 ha più di un milione di puntatori alle tuple. La ricerca di una tupla richiede quindi 4+1 accessi. 2 L’altezza di un albero è di norma 3-4. ESEMPIO. Assumendo m=34 e che ogni nodo sia completo al 100%, avremo la seguente situazione: o LIVELLO 1: 1 nodo (radice), 33 chiavi, 34 puntatori o LIVELLO 2: 34 nodi, 33*34=1112 chiavi, 34*34=1146 puntatori o LIVELLO 3: 1112 nodi, 1112*33=37.026 chiavi, 1112*34 = 38.148 puntatori o LIVELLO 4: 38.148 nodi, 1.258.884 chiavi, 1.297.032 puntatori Una ricerca in una relazione 1.300.000 tuple costa dunque 4 accessi. Se si facesse una ricerca binaria, nell’ipotesi di LR=100 e LP=1024, il costo sarebbe pari a circa 17 pagine. Se l’attributo di indicizzazione della relazione R (di 30.000 tuple) dell’esempio precedente ha valori univoci (non ammette duplicati) sono quindi necessari 3 livelli (per memorizzare 30.000 chiavi). Se invece l’attributo ammette duplicati, potrebbero bastare meno di 3 livelli. Se il B+-tree è un indice primario, in genere le foglie memorizzano le tuple (indice clustered). Si noti che in tal caso, essendo le foglie riempite parzialmente, l’occupazione di memoria è maggiore di quella che si avrebbe con una memorizzazione heap o ordinata. Se l’indice è secondario: o clustered: la relazione è ordinata sull’attributo di indicizzazione; ogni chiave in un nodo foglia punta alla pagina che contiene la prima tupla con un dato valore dell’attributo o non clustered: la relazione non è ordinata sull’attributo di indicizzazione. Siccome esistono i duplicati, ogni puntatore delle foglie punta ad un blocco di indici che contiene i puntatori a tutte le tuple con un dato valore della chiave. Implementazione Operatori Relazionali con gli indici Gli operatori dell’algebra relazionale possono essere implementati in modi diversi, a seconda del tipo di organizzazione fisica delle relazioni coinvolte. Selezione - Esempio: σ(A=a and B=b) (R) 1. in presenza di indici su A e/o B: si sceglie quello più selettivo per la selezione primaria; il costo dipende da vari fattori: A è chiave primaria? Il file è ordinato rispetto ad A? Come è implementato l’indice?. • A è chiave (o comunque non ammette duplicati), l’indice è un B+-tree. Allora il costo è dato dalla seguente: C=h+1 • A non è chiave (ammette duplicati), R è ordinata su A, l’indice secondario è un B+-tree (indice di cluster) di altezza h. Allora il costo è dato dalla seguente formula: C = h+1+ sel(A=a) * pages(R) • A è chiave (o comunque non ammette duplicati), R non è ordinata su A, l’indice secondario è un B+-tree di altezza h. Allora il costo è dato dalla seguente formula: C = h+1 • A ammette duplicati, R non è ordinata su A, l’indice secondario è un B+-tree di altezza h. Allora il costo è dato dalla seguente formula:C = h+1+1 + Sel(A=a)*Card(R) 2. uso di funzione hash se definita su A o B 3 Join: R ⊗ S. • Nested loop con R esterna: C = Pages(R)+Pages(R)*Pages(S) for each page r of R transfer r in main memory for each page s of S transfer s in main memory join each tuple in r with each tuple in s • Index nested loop: assumiamo che la condizione di join sia R.A = S.B; se esiste un indice (ad es., B+-tree) sull’attributo di giunzione B di S, questo può essere usato per implementare la suddetta condizione; se l’indice è di ordinamento (clustered) allora il costo è: C= Pages(R) + n * (h+ 1+sel(B=a) * pages(R) ), dove n è la cardinalità di R ed a è un generico valore dell’attributo A di R (per semplicità, si assume una distribuzione uniforme dei valori di A) for each page r of R transfer r in main memory for each tuple of r let r.a be the value of the join attribute search the first s.a through the B+-tree scan the pages of S for each tuple s of S with s.a join r and s • SortMerge: R e S sono ordinate rispetto agli attributi di giunzione A e B. Se A è chiave primaria di R, l’algoritmo è il seguente: r = prima tupla di R s = prima tupla di S while (r != null and s !=null) if r[A] = s[B] {aggiungi <r, s> al risultato s+;} else if r[A] < s[B] r++ else s++ Il costo è C= Pages(R)+ Pages(S) ESEMPIO. La relazione IMP ha un indice secondario B+-tree sull’attributo Dip. La relazione DIP ha un indice primario hash sull’attributo codice. IMP ha 10.000 tuple memorizzate su 2.000 pagine. DIP ha 125 tuple memorizzate su 13 pagine. Il B+-tree ha 3 livelli. Ogni DIP ha in media 10.000/125=80 IMP. IMP non è ordinato su Dip. Quindi il B+-tree ha un ulteriore livello che contiene i blocchi di puntatori Costi del join: 4 1) 2) 3) 4) nested loop, IMP X DIP C = 2000+(13*2000) = 28.000 pagine nested loop, DIP X IMO, C = 13+(13*2000) = 26.013 Uso hash su DIP con IMP esterno C = 2.000 + 10.000 = 12.000 Uso B+tree su IMP con DIP esterno C = 13 + 125(3+1 + 80) = 10.500 5