Premessa
Portale di appartenenza: Basi di dati.
Cosa troverai in questa nota:
- L’importanza dell’ottimizzazione delle interrogazioni in un DBMS di tipo relazionale.
- La distinzione tra ottimizzazione logica e ottimizzazione fisica.
- L’algoritmo secondo cui agisce l’ottimizzazione logica.
Prerequisiti: per comprendere pienamente il contenuto di questa nota, oltre le conoscenze minime che do per scontato che tu sappia già, ti consiglio di aver letto in precedenza queste altre note:
Buona lettura! ☝️🤓
Definizione: ottimizzazione delle interrogazioni
L’ottimizzazione delle interrogazioni è quell’insieme di tecniche che rendono l’implementazione delle interrogazioni il più veloce possibile. Si può svolgere su due tipi di risorse:
- Spazio: inteso come memoria, al giorno d’oggi non rappresenta più un problema nella maggior parte dei casi, data la mole di memoria a disposizione nei nostri dispositivi.
- Tempo: inteso come tempo di esecuzione delle istruzioni, su cui è importante concentrarsi per assicurare una risposta rapida da parte del DBMS.
In questa nota, in particolare, ci occuperemo dell’ottimizzazione delle interrogazioni nei DBMS di tipo relazionale.
1 - Perché serve l’ottimizzazione?
Un’interrogazione, solitamente, segue questo workflow:
- Invio della richiesta: l’applicazione, salvata in memoria centrale (RAM), invia un’interrogazione al DBMS che gestisce la [base di dati](Basi di dati.md).
- Gestione della memoria del DBMS: il DBMS controlla se il dato richiesto è già in memoria centrale o se deve essere recuperato da una periferica di archiviazione (es. SSD, HDD, CD, ecc.). La memoria centrale è molto veloce, lavora nell’ordine dei nanosecondi ( secondi).
- Eventuale caricamento dalla periferica: se il dato voluto dal DBMS non è in RAM, bisogna leggere il dato dalla periferica di archiviazione caricando pagine (blocchi di memoria). L’accesso alle periferiche come dischi rigidi o SSD è un’operazione drasticamente più lenta, effettuata nell’ordine dei millisecondi ( secondi) per gli HDD e microsecondi ( secondi) per gli SSD.
- Arrivo del dato nel buffer: il buffer manager del DBMS gestisce quali pagine tenere in RAM e quali eliminare quando la memoria è piena. Se il dato richiesto è ora in RAM, l’applicazione può leggerlo velocemente.
- Uso del dato: una volta che il dato è disponibile in memoria centrale, l’app può elaborarlo molto rapidamente.
Tenendo conto che la complessità delle attività “algoritmiche” del DBMS in memoria principale è minima (in quanto il DBMS deve gestire solo cicli, confronti, copia e trasferimento di dati), ciò che davvero fa la differenza è il numero di trasferimento di pagine, ossia il numero di letture da disco: quest’operazione è un milione di volte più lenta rispetto all’acceso di un dato nella RAM.
2 - Ottimizzazione in due fasi
Tutti i DBMS realizzano l’ottimizzazione delle interrogazioni (espresse tramite l’uso dell’algebra relazionale) attraverso due fasi: l’ottimizzazione logica e l’ottimizzazione fisica.
2.1 - Ottimizzazione logica
Definizione: ottimizzazione logica
L’ottimizzazione logica consiste nel prendere in input l’albero sintattico dell’interrogazione scritta dall’utente e trasformarlo sfruttando le proprietà dell’algebra relazionale in un albero perfettamente equivalente ma ottimizzato. È indipendente dalle strutture di memorizzazione usate.
2.1.1 - L’euristica dell’ottimizzazione logica
Nell’ottimizzazione logica, l’ottimizzatore è guidato da un semplice principio euristico: se l’interrogazione da un punto di vista logico può arrivare a coinvolgere una massa di tupla notevole (pensiamo, al prodotto cartesiano, usato nelle operazioni di theta-join e suoi derivati, che coinvolge tutti i record delle due relazioni su cui si sta effettuando l’operazione), allora il suo obiettivo deve essere quello di ridurre il più drasticamente possibile il numero di tuple coinvolte dall’interrogazione.
Si è dimostrato nei fatti che quando l’ottimizzatore fisico deve lavorare sui dati, produce risultati migliori (dal punto di vista dell’efficienza temporale) se riceve in input un albero sintattico che ha ridotto il numero di tuple concettualmente coinvolte dall’interrogazione. L’influenza positiva dell’ottimizzazione logica si riscontra nelle grandi applicazioni gestionali dei sistemi informativi (la maggioranza delle applicazioni su basi di dati. In generale, però, l’euristica non è necessariamente sempre valida.
2.1.2 - L’importanza degli operatori di selezione e proiezione
Quasi tutte le operazioni principali dei sistemi informativi che usiamo quotidianamente sono mirate a lavorare su pochissimi dati, in particolare su una determinata porzione che ci interessa dell’intera base di dati su cui poggia il sistema a cui ci interfacciamo.
Ecco quindi che entra il gioco l’operatore della selezione: grazie ad esso, infatti, è possibile porre l’attenzione su un numero limitato di record, diminuendo quelli coinvolti nelle operazioni e aumentando l’efficienza dell’interrogazione.
Ricordiamo che la selezione gode della proprietà distributiva rispetto alla proiezione, all’unione, all’intersezione, alla differenza, al prodotto cartesiano e al theta join: ciò significa che, in ogni interrogazione in cui viene usato, possiamo spostare il momento in cui lo applichiamo a nostro piacimento e quindi, in questo caso, all’inizio dell’albero sintattico per ridurre fin da subito il numero di tuple coinvolte nelle operazioni.
Allo stesso modo, si può fare lo stesso identico discorso per quanto riguarda l’operatore della proiezione, che ci permette di ridurre il numero di attributi su cui lavorare.
2.1.3 - Algoritmo di ottimizzazione logica
Algoritmo di ottimizzazione logica
- Usare la proprietà associativa della selezione multipla per decomporre selezioni singole in selezioni multiple.
- Usare le proprietà distributive della selezione per trasferire le selezioni verso le foglie dell’albero sintattico.
- Usare le proprietà distributive della proiezione per trasferire le proiezioni verso le foglie dell’albero sintattico.
- Usare la proprietà associativa della selezione multipla per ricomporre le selezioni multiple in selezioni singole.
- Ricondurre le combinazioni di selezioni e prodotti cartesiani a theta-join.
- Usare la proprietà associativa della proiezione multipla per ricomporre le proiezioni singole in proiezioni multiple.
- Scegliere la variante dell’albero sintattico di costo minimo tra quelle che si possono ottenere dall’applicazione delle proprietà associative delle operazioni.
Osservazione: spiegazione del passo 1 dell'algoritmo di ottimizzazione logica
Analizziamo il passo 1 dell’algoritmo di ottimizzazione logica:
- Usare la proprietà associativa della selezione multipla per decomporre selezioni singole in selezioni multiple.
Ci serve compiere questo passo perché la proprietà distributiva della selezione rispetto al theta-join è valida solo se gli attributi su cui è definito il predicato della selezione sono contenuti nello schema della relazione su cui viene applicata. Per esempio, su una relazione
si può applicare la selezione
ma non la selezione
perché l’attributo non fa parte dello schema di .
Ciò implica che, a una selezione con un predicato definito su più relazioni, difficilmente può essere applicata la proprietà distributiva rispetto al theta-join. Tuttavia, se spezzo la selezione in selezioni multiple, è più facile che i singoli predicati soddisfino la condizione necessaria all’applicazione della proprietà distributiva.
Osservazione: spiegazione del passo 4 dell'algoritmo di ottimizzazione logica
Analizziamo il passo 4 dell’algoritmo di ottimizzazione logica:
- Usare la proprietà associativa della selezione multipla per ricomporre le selezioni multiple in selezioni singole.
Questo passo ci risulta utile all’ottimizzazione perché, a forza di trasferire le selezioni verso le foglie dell’albero sintattico, esse si accumulano in cascata, quindi l’ottimizzatore ricompone insieme le selezioni multiple, applicando una sola selezione con un predicato formato da una congiunzione di confronti.
Osservazione: spiegazione del passo 5 dell'algoritmo di ottimizzazione logica
Analizziamo il passo 5 dell’algoritmo di ottimizzazione logica:
- Ricondurre le combinazioni di selezioni e prodotti cartesiani a theta-join.
È Importante svolgere questa operazione perché tutti i DBMS hanno algoritmi ottimizzati per l’esecuzione delle operazioni di theta-join in modo molto più efficiente rispetto all’esecuzione separata di una selezione su un prodotto cartesiano.
Osservazione: spiegazione del passo 7 dell'algoritmo di ottimizzazione logica
Analizziamo il passo 7 dell’algoritmo di ottimizzazione logica:
- Scegliere la variante dell’albero sintattico di costo minimo tra quelle che si possono ottenere dall’applicazione delle proprietà associative delle operazioni.
Il passo 7 consiste essenzialmente nella ricerca di parentesizzazioni alternative dell’albero sintattico per ridurre il costo causato dalle operazioni di theta-join (e suoi derivati come l’equi-join e il natural-join). Questo passo ha delle difficoltà computazionali non indifferenti. Per esempio, con una sequenza di theta-join, le configurazioni possibili crescono esponenzialmente:
Gli ottimizzatori, ovviamente, non esplorano tutte le possibili configurazioni (es. con , si otterrebbero possibili configurazioni, troppe da poter essere esplorate una per una), ma cercano una configurazione subottimale.
La scelta dell’ottimizzatore, quindi, è quella di anticipare il prima possibile i theta-join tra relazione con cardinalità bassa, anche perché il theta-join può lavorare su una massa di tuple enorme, ma solitamente, in uscita, produce un numero di tuple limitato (grazie alla selezione di cui è composto).
[!esercizio] Esercizio
Dato lo schema R1(AB), R2(CDE), R3(FGH), disegnare l’albero sintattico della seguente query e ottimizzarlo logicamente limitandosi agli aspetti non quantitativi.
Questa domanda non ha una valutazione automatica. Puoi scrivere la risposta su un foglio e confrontarla in seguito con la risposta giusta.
[!esercizio] Esercizio dalla prova d’esame 17/12/24
Con riferimento alla base di dati “Titoli” e i seguenti dati quantitativi:
- CARD(SQUADRA) = 500
- CARD(CONQUISTA) = 1000
- MIN(AnnoConquista, CONQUISTA) = 1900
- MAX(AnnoConquista, CONQUISTA) = 2020
disegnare gli alberi sintattici prima e dopo l’ottimizzazione logica e calcolare il numero di tuple “mosse” prima e dopo l’ottimizzazione logica della seguente query:
[!soluzione] Soluzione
Ottimizzazione dell’albero sintattico:
- Dividiamo le selezioni singole in selezioni multiple
- Spostiamo le selezioni verso le foglie:
- Spostiamo le proiezioni
- Riaccorpiamo le selezioni singole in selezioni multiple:
- Ricostituire i theta-join
- Riaccorpare le proiezioni
- Scegliere variante di costo minore
Ora calcoliamo il costo delle due query. Query originale:
Query ottimizzata:
2.1.4 - Stima del costo della selezione e fattore di selettività
L’analisi quantitativa dell’interrogazione permette di predire ex ante la cardinalità della relazione del risultato senza eseguirla. In particolare, data una relazione possiamo provare a predire la cardinalità del risultato della selezione attraverso un fattore di selettività che prende come argomento il predicato :
Il fattore di selettività è legato al solo predicato ed è un valore decimale che varia tra e interpretabile come la probabilità che un record in soddisfi il predicato , ovvero la stima della percentuale di record che soddisfano il predicato di selezione.
I DBMS mantengono in memoria una serie di informazioni di tipo statistico su ogni relazione con istanza . In particolare calcolano e salvano in memoria:
- : la cardinalità della relazione .
- : l’ampiezza dei record in byte.
- : il numero di valori distinti che appaiono nell’attributo all’interno della relazione .
- : il valore minimo dell’attributo all’interno della relazione .
- : il valore massimo dell’attributo all’interno della relazione .
I DBMS hanno a disposizione un formulario molto avanzato per il calcolo del fattore di selettività, però noi per comodità forniremo una versione più grossolana, ma sufficiente ai nostri scopi. Considereremo quindi una distribuzione uniforme dei valori all’interno dei vari attributi. Ecco una tabella per calcolare approssimativamente il fattore di selettività secondo la struttura del predicato che confronta i valori di ogni tupla in corrispondenza di un determinato attributo rispetto a un valore (o una coppia ordinata con ):
| Predicato | Valore di |
|---|---|
La seguente tabella, invece, permette di stimare il fattore di selettività su uno o più predicati combinati con gli operatori logici:
| Predicati | Valore di |
|---|---|
Esempio: stima del costo dell'equi-join
Date due relazioni ed (con ) e due attributi e , stimiamo il costo dell’equi-join tra questi:
Sappiamo già che, nel caso specifico in cui è una chiave primaria con vincolo di integrità referenziale su , la cardinalità dell’operazione è:
Tralasciando però questo caso specifico, consideriamo che l’equi-join associa a ogni tupla in con valore (ossia ) una o più tuple in con valore (). Secondo la tabella del calcolo del fattore di selettività, abbiamo la seguente stima:
Estendendo questo calcolo da ogni singola tupla a tutta la relazione , otteniamo:
Viceversa, se consideriamo le associazioni di ogni tupla in con valore (ossia ) a una o più tuple in con valore (), otteniamo la stima:
E, estendendo il calcolo da ogni singola tupla a tutta la relazione , otteniamo:
Tra le due opzioni, nel risultato finale cambia solo il valore ottenuto dal fattore di selettività: quale dei due dobbiamo scegliere?
Se consideriamo che entrambe sono delle sovrastime, possiamo considerare il valore minimo tra i due. Quindi possiamo stabilire che la cardinalità del risultato di una equi-join si può stimare come:
2.2 - Ottimizzazione fisica
Definizione: ottimizzazione fisica
L’ottimizzazione fisica consiste nel migliorare l’efficienza dell’interrogazione attraverso l’analisi delle strutture dati in cui è memorizzata la base di dati. Nell’ottimizzazione fisica si prende in input il risultato dell’ottimizzazione logica e si analizza ogni operatore all’interno dell’albero sintattico per vedere quali relazioni coinvolge e, di conseguenza, scegliere quale algoritmo applicare per rendere ottimale l’esecuzione di ogni operazione.
Approfondimento
Fonti:
- 🏫 Lezioni e slide del Prof. Pensa Ruggero Gaetano del corso di Basi di Dati (canale B), Corso di Laurea in Informatica presso l’Università di Torino, A.A. 2024-25:
- 🏫 Appunti di Luca Barra del corso di Basi di Dati, Corso di Laurea in Informatica presso l’Università di Torino, A.A. 2022-23 (caricati sul repository GitHub del Team Studentesco Informatica).