
EXPLAIN, optimization e performance tuning
EXPLAIN, optimization e performance tuning. Lezione core del modulo Advanced SQL for Analytical Systems con problema reale, modello concettuale, formalizzazione rigorosa, caso applicato, lab a 3 livelli e checkpoint finale.
Cosa imparerai
- Comprendere il problema analitico e il contesto decisionale
- Applicare esempi, metriche e controlli a casi reali
Collegamenti
EXPLAIN, ottimizzazione e tuning delle performance
Lunedì mattina, il dashboard impiega dodici minuti a caricare, il PM chiede un filtro in più e il costo del warehouse continua a salire senza che la query diventi più stabile. La tentazione è riscrivere tutto da capo. Prima però conviene capire cosa sta facendo davvero il motore di database, e per quello si parte dal query plan, non dall’intuizione.
Il problema che si vuole risolvere
Con le query analitiche complesse la difficoltà è doppia: scriverle corrette e tenerle veloci, anche quando grain, finestre, coorti e casi limite complicano la logica. Il tuning non è un esercizio accademico per far girare i numeri più in fretta. È il modo di rendere affidabili le decisioni che da quei numeri dipendono, con dati su cui ci si può appoggiare e azioni concrete da prendere.
Come ragionare prima di intervenire
Conviene tenere a mente uno schema semplice che lega la domanda al dato, il dato al controllo e il controllo all’azione. Ogni intervento tecnico, dall’aggiunta di un indice alla riscrittura di un join, ha senso solo se rafforza almeno uno di questi passaggi.
| Fase | Cosa chiarire | Output |
|---|---|---|
| Domanda | Quale scelta reale deve migliorare? | Decisione da prendere |
| Misura | Quale segnale osservabile rappresenta il problema? | Metrica o dato sorgente |
| Controllo | Quale baseline rende il risultato interpretabile? | Confronto credibile |
| Azione | Che cosa cambia dopo l’analisi? | Prossimo passo operativo |
Lo schema operativo
Prima di toccare EXPLAIN conviene fissare alcuni punti. L’unità di lavoro va dichiarata, che si tratti di righe, partizioni, finestre, join, coorti o metriche temporali. Va scelto il segnale principale tra correttezza, performance, presenza di duplicati, grain e stabilità. Serve una baseline, di solito il periodo precedente, un gruppo comparabile o un benchmark. Va detto cosa ci si aspetta di produrre, sia esso una query, un modello, un test o un pattern riusabile. E va riconosciuto il rischio, che resta sempre lo stesso: confondere un numero con una prova.
| Elemento | Specifica richiesta |
|---|---|
| Unità di analisi | riga, partizione, finestra, join, coorte o metrica temporale |
| Segnale | correttezza, performance, duplicati, grain, stabilità |
| Baseline | periodo precedente, gruppo comparabile, benchmark o controfattuale |
| Decisione | query, modello intermedio, test SQL o pattern riusabile |
| Rischio | scambiare un numero disponibile per una prova sufficiente |
Lo schema regge quando un altro analista può riprodurre la logica e arrivare alla stessa decisione.
Leggere EXPLAIN: anatomia di un query plan
EXPLAIN mostra cosa fa il database con la query: quali scansioni esegue, come unisce le tabelle, dove aggrega e dove filtra. Vale la pena conoscere le operazioni più ricorrenti e sapere quando devono far suonare un campanello.
| Operazione | Significato | Allarme se… |
|---|---|---|
| Seq Scan / Full Scan | Legge tutta la tabella | Solo su tabelle piccole o quando serve tutto |
| Index Scan | Usa un indice per trovare righe | Buono se selettivo |
| Index Only Scan | L’indice copre tutte le colonne | Ottimo, nessun accesso alla tabella |
| Hash Join | Costruisce una hash table in memoria | OK se la tabella inner è piccola; allarme se grande |
| Nested Loop | Per ogni riga di A cerca in B | Allarme se B è grande e senza indice |
| Sort | Ordina dati (GROUP BY, ORDER BY) | Allarme se sort su disco (memoria insufficiente) |
Caso reale in PostgreSQL
EXPLAIN ANALYZE
SELECT c.name, COUNT(o.id)
FROM customers c
JOIN orders o ON c.id = o.customer_id
WHERE c.country = 'IT'
AND o.order_date >= '2024-01-01'
GROUP BY c.name;
L’output mostra due Seq Scan, un Hash Join e un HashAggregate in memoria. Il collo di bottiglia è la lettura completa di orders, che conta 1.2M righe. Aggiungendo un indice su orders(customer_id, order_date), la Seq Scan diventa Index Only Scan e il tempo cala del 70%.
Strategie di ottimizzazione: una gerarchia di interventi
Gli interventi non hanno tutti lo stesso peso, e conviene affrontarli in ordine. Il primo guadagno arriva quasi sempre riducendo il volume di dati letto, cioè filtrando presto con WHERE su colonne indicizzate o partizionate. Poi si alleggerisce il lavoro di join, usando anti-join, semi-join o pre-aggregazioni dove la logica lo permette. A seguire vengono gli indici compositi e parziali, scelti in modo che coprano le colonne effettivamente richieste. Solo alla fine si mette mano alla memoria per sort e hash join, attraverso parametri come work_mem e join_buffer_size. Saltare l’ordine, partendo dai parametri di memoria su una query che legge tutto, di solito sposta poco.
ClickHouse: un paradigma diverso
ClickHouse è column-oriented e memorizza ogni colonna separatamente. Questo gli permette di leggere solo le colonne che servono, ed è il motivo per cui regge bene le query analitiche su grandi dataset.
Le leve di ottimizzazione qui sono altre. L’ORDER BY della tabella funziona da indice primario e consente di saltare i blocchi inutili. I codec di compressione riducono lo spazio occupato e accelerano la decompressione. Le materialized column spostano all’INSERT il calcolo delle espressioni costose, così non vanno rifatte a ogni query. Le projection, infine, sono mini-tabelle ordinate in modo diverso e pensate per le query più frequenti.
Caso reale: Cloudflare
Cloudflare ha portato una query di aggregazione da 45 a 0.8 secondi con una sola mossa: una materialized column che calcola il paese a partire dall’IP al momento dell’INSERT, evitando di rifare quel calcolo a ogni interrogazione.
Esercizio
Per allenarsi serve un dataset realistico: una tabella orders da 5M righe e una customers da 500K righe vanno benissimo. Si comincia eseguendo EXPLAIN ANALYZE su una query con join e aggregazione e individuando il collo di bottiglia. Poi si aggiunge un indice mirato e si verifica quanto cambia il piano. Infine si riscrive la query usando un anti-join o una pre-aggregazione, confrontando i due piani per capire dove è andato il guadagno.
Vale la pena chiudere l’esercizio con un passaggio decisionale, non solo tecnico. Scrivi quale decisione concreta questa analisi dovrebbe migliorare, qual è la metrica principale e quale rischio va tenuto sotto controllo. Poi costruisci una piccola tabella che metta in fila baseline, segnale osservato, interpretazione prudente e azione consigliata. Chi vuole spingersi oltre può trasformare il tutto in un memo decisionale, con assunzioni esplicite, limiti, criterio di stop e controllo successivo. Come materiale vanno bene un export reale, un dataset sintetico o una dashboard già esistente, purché contengano una domanda, una metrica e una scelta da prendere.
Errore tipico da evitare
L’errore ricorrente è usare EXPLAIN e tuning come etichetta invece che come processo: mostrare grafici senza una decisione collegata, metriche senza baseline, conclusioni senza riconoscere i rischi. C’è una domanda che smaschera subito il problema: se i dati fossero instabili, quale scelta sbaglieresti? Se non sai rispondere, il legame tra analisi e azione non c’è ancora, e nessuna ottimizzazione lo crea al posto tuo.
Domande di controllo
Per fissare le idee, prova a rispondere a queste domande. Quando una Seq Scan è accettabile e quando invece è un problema? Qual è la gerarchia con cui affrontare l’ottimizzazione di una query SQL? Perché ClickHouse è più veloce sulle query analitiche che toccano poche colonne? Cosa sono le materialized column e quale costo spostano? E, la domanda che lega tutto, come si traduce un piano EXPLAIN in una decisione concreta da presentare a chi non legge query?
Riepilogo operativo
EXPLAIN, ottimizzazione e tuning diventano strumenti decisionali solo quando producono scelte chiare e azioni concrete, non quando si fermano al grafico più veloce. La disciplina sta nel collegare dati, modelli e decisioni in un processo che un’altra persona può ripetere e contestare. Applica questo metodo a una decisione reale: chiediti quale scelta deve cambiare, quale evidenza hai in mano, quali assunzioni stai facendo e quale rischio resta aperto. Se il caso non rende visibile questo passaggio, non è ancora pronto per essere automatizzato.
Percorso collegato
Lezioni da leggere insieme
Questi collegamenti portano la lezione dentro il resto del corso: basi da riprendere, passaggi successivi e connessioni tematiche tra moduli.