Normalizzazione
Nelle precedente lezione abbiamo approfondito il concetto di chiave primaria, superchiave e chiave esterna, e di come l’entità non è solo una associazione di un insieme di attributi, ma è definita come un concetto informativo definito da uno o attributi chiave, ed un insieme di attributi ad essa dipendenti.
Questa concezione del database è l’obiettivo ultimo della progettazione, e va verificata a livello di schema logico, prima di procedere oltre. Dobbiamo capire cioè se le tabelle che stiamo creando sono proprio tutte e sole quelle che ci servono, o è necessario gestire ridondanze, dati duplicati e che siano in grado di evitare problemi quando andremo ad inserire o cancellare dati.
Questa operazione viene chiamata normalizzazione. Essa consente, in modo formale, la verifica delle tabelle e dell’assocazione degli attributi delle stesse. Ha come scopo quello di verificare non solo che esista una chiave per ogni tabella, ma che tutti gli attributi dipendano SOLO dalla chiave, in caso contrario c’è una qualche anomalia di progettazione del database. Ad esempio la normalizzazione va a verificare che non si creino situazioni come quella della tabella Excel degli ordini vista nella lezione precedente.
La normalizzazione si basa sul concetto di dipendenza funzionale:
- dato X come sottoinsieme di uno o più attributi
- dato Y come sottoinsieme di uno o più attributi
- Y dipende da X (X -> Y) se il valore degli attributi di Y dipende SOLO dai valori degli attributi X.
Ad esempio:
- nome e cognome (Y) dipendono da codice fiscale (X)
- nome e cognome (Y) dipendono da matricola (X)
- matricola NON dipende da nome e cognome (ci possono essere studenti omonimi)
- email NON dipende da nome e cognome
Quando analizziamo una tabella applicando la normalizzazione, verifichiamo che siano verificate progressivamente regole via via più restrittive di normalizzazione, dette forme normali. Sono previste 4 forme normali progressive, dalla prima alla terza, ed infine la la forma più restrittiva, detta di Boyce-Codd.
Prima forma normale (1NF)
Una tabella è in prima forma normale se e solo se contiene campi atomici, cioè senza valori ripetuti.
Ad esempio:
| CodiceCorso | NomeCorso | Libri |
|---|---|---|
| INF-01 | Programmazione | “Python”, “Strutture dati” |
Questa tabella non è in forma normale, perché la colonna Libri ha più di un valore.
Per normalizzarla è sufficiente scomporre gli attributi multipli:
| CodiceCorso | NomeCorso | Libri |
|---|---|---|
| INF-01 | Programmazione | Python |
| INF-01 | Programmazione | Strutture di dati |
Seconda forma normale (2NF)
Una tabella è in seconda forma normale se è prima forma normale E se ogni attributo dipende interamente dalla chiave, e non da parte di essa. Riprendiamo la precedente tabella:
| CodiceCorso | NomeCorso | Libro |
|---|---|---|
| INF-01 | Programmazione | Python |
| INF-01 | Programmazione | Strutture di dati |
Come si può vedere la chiave primaria è necessariamente {CodiceCorso, Libro}. Tuttavia NomeCorso non dipende da questa chiave composta, ma solo da parte di essa, ovvero CodiceCorso.
Per normalizzare occorre quindi creare due tabelle:

Terza forma normale (3NF)
Una tabella è in terza forma normale se è in seconda forma normale e nessun attributo non chiave dipende in modo transitivo (indiretto) dalla chiave primaria. Ovvero non deve verificarsi la situazione in cui l’attributo A dipende dall’attributo B, che dipende dall’attributo C.
Ad esempio prendiamo questa tabella:
| Matricola | CorsoDiLaurea | Sede |
|---|---|---|
| 726265 | Informatica | Festa del Perdono |
| 726266 | Lettere classiche | Città studi |
| 726267 | Giurisprudenza | Conservatorio |
| 726268 | Chimica | Città Studi |
Se osserviamo bene c’è una anomalia macroscopica: la sede dipende dal corso di laurea, e NON dalla matricola. Per normalizzare bisogna creare due tabelle:

Forma normale di Boyce-Codd (BCNF)
Una tabella è in forma normale di Boyce-Codd se è in terza forma normale, ed ogni attributo non chiave deve dipendere da un attributo che deve essere superchiave, anche se non è chiave primaria. Per capire meglio questo scenario vediamo questo esempio di tabella:
| Materia | Docente | Ruolo |
|---|---|---|
| Programmazione I | prof. Rossi | teoria |
| Programmazione I | prof. Russo | laboratorio |
| Reti di calcolatori | prof. Rossi | teoria |
La tabella ha come chiave {Materia, Docente}. E’ immediatamente visibile che è 1NF, inoltre è anche in 2NF, perché ruolo dipende dalla coppia {Materia, Docente} e non solo da uno di essi. E’ anche in 3NF, perché Ruolo non dipende da attributi non chiave. Eppure non è in forma normale, perché concettualmente nel mondo reale, il ruolo dipende dal docente, non dalla coppia docente-materia. In altri termini entrambe queste affermazioni sono entrambe vere:
- il ruolo di Rossi è di docente di teoria per programmazione I
- Rossi però è docente di teoria sempre, non solo per quella materia
La prima informazione è soddisfatta dalla 3NF, ma la seconda no. Bisogna creare un’altra tabella per soddisfare il requisito:

Normalizzazione e progettazione
La normalizzazione e quindi la progettazione corretta del database ha un impatto significativo nella fase di popolamento e gestione dei dati del database in tutti gli scenari reali:
- inserimento: grazie alla normalizzazione si evita la ridondanza in inserimento, evitando valori duplicati: ad esempio se inseriamo un nuovo corso con il docente (esempio di BCNF) non ci dobbiamo ricordare che ruolo aveva quel docente, perché c’è un’altra tabella che già ce lo dice;
- modifica: se si cambia il contenuto di un record, ad esempio cambia la sede del corso di laurea (vedi esempio della 3NF), è sufficiente cambiarlo in un solo punto, e tutte le tabelle collegate continueranno a funzionare;
- cancellazione: se si elimina un record da una tabella, ad esempio un docente va in pensione, si può automatizzare una regola che cancella, in cascata, tutti i corsi che teneva quel docente, senza rischi di dati inconsistenti.
Denormalizzazione
La normalizzazione ha come scopo ultimo l’efficienza dal punto di vista della ridondanza dei dati. E’ importante però capire che nel mondo reale la normalizzazione può portare a creare un numero eccessivo di tabelle. Ad esempio, con la forma normale di Boyce-Codd abbiamo suddiviso la tabella che associa corso, docente e ruolo in due tabelle, una che associa corso e docente e l’altra che associa docente al ruolo. Questa efficienza però ha un costo computazionale: quando andremo ad elencare l’elenco dei corsi dovremo per forza unire le due tabelle, con una operazione che come vedremo si chiama “join”, operazione che richiede un tempo computazionale maggiore rispetto ad una tabella non normalizzata.
E’ un classico problema di tradeoff: una struttura matematicamente efficiente può non esserlo nell’applicazione pratica. In questo caso bisogna includere nell’analisi gli effettivi utilizzi reali dei dati: se le due tabelle sono in effetti utilizzate sempre insieme, conviene avere un po’ di ridondanza dei dati, e quindi utilizzare la tabella in terza forma normale (con 3 colonne) ma risparmiare poi sul tempo di lettura. Questa operazione prende il nome di denormalizzazione, di norma dalla BCNF alla 3NF (non è mai conveniente invece scendere alla 2NF). E’ una scelta questa comunque che si acquisisce con l’esperienza e molta pratica.
