Sei sulla pagina 1di 31

Progettazione Database Relazionali

Fondamenti
Sommario
Introduzione ......................................................................................................................................... 3
Il Modello Relazionale ..................................................................................................................... 3
Progettazione di database relazionali ................................................................................................... 4
Tabelle, unicità e chiavi ................................................................................................................... 4
Chiavi esterne e domini.................................................................................................................... 6
Relazioni .......................................................................................................................................... 7
Relazioni uno-a-uno ..................................................................................................................... 7
Relazioni uno-a-molti .................................................................................................................. 8
Relazioni molti-a-molti ................................................................................................................ 9
Normalizzazione ............................................................................................................................ 10
Relazioni e normalizzazione ...................................................................................................... 10
Prima Forma Normale (1FN) ..................................................................................................... 11
Seconda forma normale ............................................................................................................. 13
Terza forma normale .................................................................................................................. 15
Altre forme normali ................................................................................................................... 17
Regole d’integrità ........................................................................................................................... 18
Regole d’integrità generali ......................................................................................................... 18
Integrità di entità .................................................................................................................... 18
Integrità referenziale .............................................................................................................. 18
Regole d’integrità specifiche della base dati .............................................................................. 19
Un approccio pratico alla progettazione ............................................................................................ 22
Modello logico ............................................................................................................................... 23
Modello fisico ................................................................................................................................ 26
Violare le regole: quando denormalizzare ..................................................................................... 28
Sommario ........................................................................................................................................... 30
Appendice .......................................................................................................................................... 31
Risorse............................................................................................................................................ 31
Introduzione
La teoria relazionale è una materia che molte persone evitano di apprendere per mancanza di tempo.
Molti altri tentano di apprenderla, ma rinunciano a causa dell’arida, accademica esposizione degli
argomenti spesso fornita da autori e insegnanti. Ma se la creazione di database1 è parte del proprio
lavoro, nel bagaglio di ogni tecnico non può mancare una solida comprensione della teoria alla sua
base.

Questi appunti iniziano con un’introduzione alla teoria relazionale e proseguono con la discussione
di concetti fondamentali quali le chiavi, le relazioni, le spesso sottovalutate “Forme Normali” e le
regole di integrità.

Seguendo la teoria, sarà presentato un pratico approccio passo-passo per l’acquisizione di una
valida metodologia di progettazione.

Il Modello Relazionale

Concepito da E. F. Codd nel 1969, allora ricercatore dell’IBM, il modello relazionale è basato su
note branche della matematica quali la Teoria degli Insiemi e la Logica dei Predicati.

L’idea alla base del modello relazionale è che un database consiste di una serie di tabelle non
ordinate (o relazioni) che possono essere manipolate usando operazioni non-procedurali che
ritornano a loro volta dati sotto forma di tabelle.
Questo modello era in netto contrasto con le teorie per le basi dati dell’epoca, molto più complicate,
meno flessibili e dipendenti dall’accesso fisico ai dati.

Nota E’ opinione comune che il termine relazionale nel modello omonimo provenga dal fatto che il
modello si fondi su relazioni fra tabelle di una base dati. Tale associazione è corretta, tuttavia non è
del tutto accurata. La parola relazionale trae infatti origine dalla terminologia che Codd usava per
definire il modello relazionale dei dati: nelle esposizioni di Codd, infatti, il termine tabella era
sostituito dal termine relazione, ad indicare un insieme di informazioni in relazione fra loro.
In effetti, Codd e gli altri teorici usano i termini relazioni, attributi e tuple dove i progettisti usano
rispettivamente i più comuni termini tabelle, colonne e righe o, in modo più prossimo allo strato
fisico – e perciò meno preferibile per discussioni teoriche – files, campi e records (vedi Tab. 1).

Tabella 1
Modello Teorico (Codd) Logico Fisico
Relazione Tabella File
Terminologia Attributo Colonna Campo
Tupla Riga Record

Il modello relazionale può essere applicato sia alle basi dati sia ai sistemi di gestione delle basi dati
(database management system - DBMS). La fedeltà al modello relazionale di un DBMS2 può essere
comparata usando le 12 regole di Codd3 (successivamente estese a 300), ma tale trattazione esula
dallo scopo di questo documento, il cui tema centrale è la progettazione di database relazionali.

1
Usiamo in modo equivalente i termini ‘database’ e ‘base dati’, essendo indifferentemente utilizzati nel linguaggio
corrente la traduzione in inglese ed il suo acronimo ‘DB’. Lo stesso vale per i termini ‘sistemi di gestione delle basi
dati’, ‘database management system’ e relativo acronimo ‘DBMS’, citati nel seguito.
2
Ovviamente ci riferiamo qui a DBMS per basi dati relationali, comunemente individuati dall’acronimo ‘RDBMS’. In
questo documento consideriamo perciò i due acronimi ‘DBMS’ e ‘RDBMS’ del tutto equivalenti.
3
Cfg. [3] The Relational Model. EF Codd. Addison Wesley
Progettazione di database relazionali
Nella progettazione di un database, è necessario prendere decisioni su come trasferire un sistema
del mondo reale in un modello su base dati. Ciò corrisponde a decidere quali tabelle creare, quali
colonne esse devono contenere, quali relazioni intercorrono tra le tabelle e quali sono i vincoli tra i
vari elementi.

Sarebbe bello se questo processo fosse totalmente intuitivo, o ancora meglio automatizzato, ma
purtroppo non è così. Una base dati ben congegnata richiede impegno e tempo per il suo
concepimento, la sua realizzazione ed il suo affinamento.

I benefici di un database disegnato in accordo con il modello relazionale sono numerosi. Per citarne
alcuni:
 Inserimento, aggiornamento, cancellazione dati efficiente.
 Recupero dati, generazione sommari e report efficiente.
 Il database si comporta in maniera predicibile, poiché segue un modello ben formulato.
 Il database è auto-documentato, poiché la maggior parte delle informazioni risiede nella
base dati piuttosto che nell’applicazione.
 Le modifiche allo schema del database sono semplici da effettuare.

L’obbiettivo di questo documento è spiegare i principi della progettazione di db relazionali ed


esemplificare questi principi utilizzando un noto DBMS come Oracle4.

La trattazione che ne consegue non vuole essere in alcun modo esaustiva e certamente non
definitiva, date le molte carriere dedicate allo studio della progettazione di database ed i molti libri
scritti al riguardo. E’ invece pensata come introduzione, breve ma chiara, per lo sviluppatore che
vuole affrontare l’argomento senza scontrarsi inutilmente con termini e formalismi che, seppure
rigorosi, non sono utilizzati nella pratica di tutti i giorni.

Tabelle, unicità e chiavi

Nel modello relazionale le tabelle sono usate per rappresentare “cose” o, più rigorosamente, “entità”
del mondo reale. Ogni tabella rappresenta una sola entità, che può essere un oggetto o un evento del
mondo reale.

Per esempio, un oggetto può essere un cliente, un elemento d’inventario o una fattura, mentre un
evento può essere la visita di un paziente, un ordine o una chiamata telefonica.

Come accennato nell’introduzione, le tabelle sono composte da righe e colonne. Il modello


relazionale impone che ogni riga in una tabella sia unica: infatti, se fosse consentita la duplicazione
di righe in una tabella, per l’applicazione che utilizza la base dati non sarebbe possibile reperire
univocamente una data riga, dando luogo ad ogni sorta di ambiguità e problemi che è bene evitare.

E’ possibile garantire l’univocità di una riga designando una chiave primaria – un insieme di dati,
definito da una colonna o combinazione di colonne, che contiene valori unici per la tabella.
Ogni tabella può avere soltanto una chiave primaria, anche se diverse colonne o combinazioni di
colonne possono contenere valori unici.

4
Gli stessi principi si possono utilizzare in modo altrettanto valido, ma con sintassi e modalità che potrebbero essere
differenti, con altri DBMS come MySQL, MS-SQL Server, MS-Access, etc.
Tutte le colonne (o combinazioni di colonne) aventi valori unici in una tabella sono definite “chiavi
candidate”. Tra le chiavi candidate è designata una “chiave primaria”, mentre le rimanenti sono
definite “chiavi alternative”.

Le chiavi possono essere semplici o composite: il termine “chiavi semplici” si riferisce alle chiavi
definite da una colonna, mentre con “chiavi composite” ci si riferisce alle chiavi definite da due o
più colonne.

La decisione rispetto a quale chiave candidata utilizzare come chiave primaria è nelle mani del
progettista. Non c’è una regola scientifica per determinare quale tra le chiavi candidate è la migliore
chiave primaria, tuttavia è possibile applicare il cosiddetto principio di minimalità, stabilità e
semplicità/familiarità5. Per tale principio una buona chiave primaria:

 ha il minor numero di colonne possibile


 difficilmente può cambiare
 è al contempo semplice e familiare per gli utenti

Illustriamo tale principio con un esempio. Diciamo che un’azienda ha una tabella di clienti chiamata
T_Customer , visualizzata in Fig. 1.

Figura 1 – Customer_Id è la scelta migliore come chiave primaria per T_Customer.

L’insieme di chiavi candidate per T_Customer include Customer_Id, (First_Name+Last_Name),


Phone, (Address, City, State), e (Address + ZipCode).

Seguendo le linee guida precedenti possiamo escludere le ultime tre candidate, dato che indirizzo e
numero di telefono possono cambiare con relativa frequenza. La scelta tra Customer_Id e
‘First_Name + Last_Name’ è meno ovvia e su tale scelta si potrebbe quindi argomentare:

 Quanto è probabile che il cognome di un cliente possa cambiare? (es. a causa di un


matrimonio)
 Quanto sono frequenti gli errori di trascrizione?
 Quanto è probabile che due clienti abbiano lo stesso nome e cognome?
 Quanto è familiare il Customer_Id per gli utenti?

Non c’è una risposta definitiva, ma molti sviluppatori optano per una chiave primaria numerica (nel
nostro esempio Customer_Id) perché i nomi a volte cambiano e perché le ricerche e gli ordinamenti
sulle colonne numeriche sono generalmente più efficienti di quelli sulle colonne di testo.

In genere le sequenze di interi forniscono una buona soluzione per le chiavi primarie, specialmente
quando si hanno diverse chiavi candidate valide e tra queste non è presente un valore numerico
identificativo.
Le sequenze di interi non sono da usarsi se è occasionalmente richiesto di rinumerare i valori – non
sarà semplice farlo e in alcuni casi non sarà nemmeno possibile.
5
Cfg. [4] SQL and Relational Basics. Fabian Pascal. M&T Books.
Inoltre, le sequenze di interi hanno senso solo per tabelle che costituiscono il lato ‘uno’ di una
relazione uno-a-molti (vedi discussione nella sezione successiva).

Nota Sono molte le situazioni in cui è preferibile utilizzare un numero intero6 arbitrario (es. ID
aziendale, una sequenza di valori, etc.) come chiave primaria piuttosto che un elemento di testo (es.
nome, descrizione, o altro). Questo eviterà conflitti di codifica, errori di trascrizione o la gestione di
cambiamenti (es. di nome) che diventerebbe rapidamente problematica.

Chiavi esterne e domini

Se le basi dati relazionali consistessero di sole tabelle non correlate le chiavi primarie non sarebbero
così utili. Le chiavi primarie diventano essenziali quando si creano relazioni che uniscono diverse
tabelle.

Il concetto di chiave esterna è usato in stretta associazione con i concetti di chiave primaria e di
relazione fra tabelle: una chiave esterna è infatti una colonna in una tabella usata come riferimento
ad una chiave primaria in un’altra tabella.

Dato un sistema del mondo reale (es. gestione ordini clienti), continuando l’esempio presentato
nell’ultima sezione, scegliendo Customer_Id come chiave primaria per T_Customer e definendo
una seconda tabella, T_Order, come mostrato in Fig. 2, Customer_Id è una chiave esterna in
T_Order poiché può essere usata come riferimento ad un dato cliente (cioè a una data riga) in
T_Customer.

Figura 2 – Customer_Id è una chiave esterna in T_Order, riferimento ad un cliente in T_Customer

E’ importante che sia le chiavi esterne sia le chiavi primarie usate come riferimento abbiano un
significato comune ed abbiano valori appartenenti allo stesso dominio, dove per ‘dominio’ si
intende un elenco al quale appartengono i valori assumibili dai dati di una determinata colonna.

Per esempio, la colonna Customer_Id è associata al dominio dei numeri interi7. In modo analogo,
una colonna ‘Sex’ potrebbe essere associata al dominio formato dai caratteri ‘M’ ed ‘F’.

6
Sono sconsigliati i numeri reali perché la loro rappresentazione da parte di un elaboratore è per sua natura inesatta.
7
Con le limitazioni (min, max) legate alla rappresentazione degli interi da parte dell’elaboratore e ad eventuali ulteriori
vincoli (es. min=0, max=50000) imposti dal sistema reale a cui si riferisce la base dati.
Le associazioni tra colonne e domini possono essere pensate come tipi definiti dall’utente, la cui
definizione implica certe regole che è necessario seguire per i valori e certe operazioni che è
possibile effettuare su di essi.

Relazioni

Come abbiamo visto, in una base dati le chiavi esterne si usano per modellare relazioni esistenti nel
mondo reale.
Le relazioni tra entità del mondo reale possono essere piuttosto complesse, coinvolgendo numerose
relazioni multiple tra entità interdipendenti.

In una famiglia, ad esempio, esistono allo stesso tempo relazioni multiple tra i differenti membri.

In una base dati relazionale, tuttavia, si considerano solo le relazioni tra coppie di tabelle, le quali
possono essere legate in uno dei modi seguenti:

 uno-a-uno
 uno-a-molti
 molti-a-molti

descritti in maggiore dettaglio nelle successive sezioni.

Relazioni uno-a-uno

Due tabelle sono in relazione uno-a-uno (1-1) se, per ogni riga nella prima tabella, c’è al più una
riga nella seconda tabella.

Relazioni effettivamente uno-a-uno raramente si incontrano nel mondo reale. Questo tipo di
relazioni è spesso creato quando occorre dividere una tabella in due o più tabelle per motivi legati
alla sicurezza o alle performance o per aggirare limitazioni del DBMS8, piuttosto che per modellare
sistemi effettivamente esistenti nel mondo reale.

Per esempio (vedi Fig. 3), si potrebbe memorizzare la maggior parte delle informazioni di un
paziente in una tabella T_Patient, e memorizzare le informazioni sensibili (es. nome, n.ro SSN, e
indirizzo) in un’altra tabella, T_Confidential, limitando l’accesso a T_Confidential solo ad alcuni
utenti.

8
Ad esempio, una relazione uno-a-uno potrebbe essere necessaria per dividere una tabella in due o più tabelle a causa
del limite di 255 colonne imposto dal DBMS in uso.
Figura 3 – Le tabelle T_Patient e T_Confidential sono in relazione uno-a-uno (chiave primaria: Patient_Id)

Come secondo esempio, nel caso si dovesse trasferire a intervalli regolari solo una porzione di
tabella in un’altra applicazione, è possibile suddividere la tabella originale in due parti (es. dati
trasferiti e dati non trasferiti), da porre in join con una relazione uno-a-uno.

Le tabelle in relazione uno-a-uno dovrebbero sempre avere la stessa chiave primaria, da utilizzarsi
come colonna di join.

Relazioni uno-a-molti

Due tabelle sono in relazione uno-a-molti9 (1-M)


se per ogni riga nella prima tabella possono
esistere zero, una o molte righe nella seconda
tabella, ma per ogni riga nella seconda tabella
esiste esattamente una riga nella prima tabella.

Per esempio, ogni ordine di una pizzeria a


domicilio può avere caratteristiche diverse (tipo,
data, ID cliente, data/ora consegna, metodo di
pagamento, etc.). Perciò, T_Order è in relazione
uno-a-molti con T_OrderDetails (vedi Fig. 4).

Le relazioni uno-a-molti sono le più comuni e


sono spesso usate per il collegamento di tabelle
base a tabelle nelle quali memorizzare
informazioni di dettaglio (lookup tables).

Figura 4 - Le tabelle T_Order e T_OrderDetails


sono in relazione uno-a-molti.

9
Anche definita relazione padre-figlio.
Relazioni molti-a-molti

Due tabelle sono in relazione molti-a-molti (M-M) quando ad ogni riga della prima tabella si
possono associare più righe della seconda tabella e per ogni riga della seconda tabella si possono
associare più righe della prima tabella.

Per esempio, un individuo può avere più polizze assicurative con compagnie diverse ed una data
compagnia di assicurazioni molto probabilmente ha più di un cliente. Perciò, una tabella
T_Customer potrebbe essere in relazione molti-a-molti con una tabella T_Insurer.

Tuttavia, le relazioni molti-a-molti non possono essere direttamente modellate in un DBMS, ma


devono essere suddivise in più relazioni uno-a-molti; a tale scopo occorrerà quindi creare una terza
tabella di collegamento.

Nel nostro esempio, una terza tabella T_InsurancePgm potrebbe contenere una riga per ogni polizza
assicurativa posseduta da ciascun individuo (vedi Fig. 5). Quindi, la relazione molti-a-molti tra
T_Customer e T_Insurer potrebbe essere suddivisa in due relazioni uno-a-molti (T_Customer e
T_Insurer in relazione uno-a-molti con T_InsurancePgm).

Figura 5 – T_InsurancePgm è usata per modellare la relazione molti-a-molti tra T_Customer e T_Insurer.
Normalizzazione

Come accennato in precedenza, quando si progetta un database è necessario confrontarsi con una
serie di scelte:

 Quante tabelle comporranno la base dati e quali entità rappresenteranno?


 Quali colonne comporranno ciascuna tabella?
 Quali relazioni intercorreranno tra le tabelle?

Le risposte a queste domande risiedono nel concetto di normalizzazione. La normalizzazione è il


processo di semplificazione del disegno di una base dati, eseguito al fine di ottenere per la base dati
una struttura ottimale.

La teoria della normalizzazione si esprime attraverso le cosiddette ‘Forme Normali’, che


costituiscono una progressione lineare di regole applicabili al disegno di una base dati.
Ciascuna forma normale:

 Prima Forma Normale (1FN)


 Seconda Forma Normale (2FN)
 Terza Forma Normale (3FN)
 Forma Normale di Boyce Codd
 Quarta Forma Normale
 Quinta Forma Normale
 Altre Forme Normali

fornisce un migliore e più efficiente livello di disegno.

Discuteremo nel seguito le prime tre forme normali. Per le restanti si rimanda ai testi in appendice10.

Relazioni e normalizzazione

Le Forme Normali si basano sulle relazioni piuttosto che sulle tabelle. Una relazione è uno speciale
tipo di tabella, con i seguenti attributi:

1. Descrive un’entità.
2. Non ha righe duplicate, quindi possiede sempre una chiave primaria.
3. Le colonne non sono ordinate.
4. Le righe non sono ordinate.

Un DBMS in genere non richiede di definire una chiave primaria per ogni tabella, ma l’esistenza di
una chiave primaria è fortemente raccomandata e, come abbiamo visto, strettamente richiesta dal
modello relazionale.
Ciò impone che, in una base dati che rispetti il modello relazionale, qualsiasi tabella debba
possedere gli attributi 1 e 2 sopracitati.
Inoltre, in qualsiasi DBMS le tabelle possiedono in genere11 gli attributi 3 and 4.

Con queste premesse, per tutti gli scopi pratici i termini tabela e relazione diventano
intercambiabili.

10
In particolare, cfg. [3] ‘The Relational Model’, EF Codd. Addison Wesley.
11
A meno di esigenze specifiche legate alla visualizzazione dei dati della tabella (es. form in MS-Access)
E’ comunque importante sottolineare che, nel seguito, con il termine ‘tabella’ ci si riferisce ad una
tabella che effettivamente corrisponde alla definizione di relazione data all’inizio di questo
paragrafio.

Prima Forma Normale (1FN)

Tutti i valori di una colonna devono essere atomici12.

La 1FN stabilisce quindi che esiste uno ed un solo valore, non un vettore o una lista di valori, per
ogni posizione riga-colonna in una data tabella.

I benefici di questa regola dovrebbero essere ovvii: se una lista di valori fosse memorizzata in una
singola colonna, non ci sarebbe un modo semplice per reperirne e manipolarne il contenuto.

L’ottenimento dei dati diventerebbe molto più laborioso e difficile da generalizzare.


Per esempio, la tabella in Fig. 6, tblOrder1, usata per memorizzare dati per un negozio di
ferramenta, viola la 1FN:

Figura 6 – T_Order1 viola la Prima Forma Normale (1FN).

E’ alquanto macchinoso recuperare tutti i dati memorizzati in questa tabella, a causa delle troppe
informazioni memorizzate nella singola colonna Items. Si pensi a come sarebbe difficoltosa la
creazione di un report che riassume le vendite categorizzandole per prodotto.

La 1FN proibisce inoltre la presenza di gruppi ripetuti di informazioni, anche se memorizzati in


colonne multiple.

Per esempio, la stessa tabella potrebbe essere migliorata sostituendo la singola colonna Items con le
sei colonne: Quant1, Item1, Quant2, Item2, Quant3, Item3 (vedi Fig. 7).

12
La parola ’atomico‘ è qui riferita al latino atomis, indivisibile.
Figura 7 – T_Order2 è una versione migliorata di T_Order1, ma i gruppi ripetuti violano la 1FN.

Nonostante il nuovo disegno abbia suddiviso l’informazione in colonne multiple, esiste ancora
qualche problema.

Per esempio, come possiamo determinare la quantità di martelli (hammers) ordinati da tutti i clienti
durante un mese specifico?

Qualsiasi query dovrebbe ricercare nelle tre colonne Item1, Item2, Item3 per determinare se è stato
ordinato un martello e quindi sommare i valori risultanti. Ancora peggio, cosa accadrebbe se un
cliente ordinasse più di tre articoli in un singolo ordine?

Si potrebbero sempre aggiungere altre colonne, ma a che punto ci si dovrebbe fermare? Sarà
sufficiente aggiungere dieci colonne? O sarà meglio aggiungerne venti?
Supponendo di aver deciso che un cliente non potrebbe richiedere più di 25 articoli in un singolo
ordine e di aver disegnato la tabella di conseguenza, come risultato occorrerebbero 50 colonne per
riga al fine di memorizzare l’informazione relativa all’articolo ed alla quantità ordinata. Questo
anche per ordini in cui è
richiesto un solo articolo,
con chiaro spreco di
spazio e senza contare
che in un giorno non
troppo lontano qualcuno
potrebbe voler ordinare
più di 25 articoli!

Le tabelle in 1FN non


presentano i problemi
delle tabelle contenenti
gruppi ripetuti. La tabella
in Fig. 8, T_Order3, è in
1FN poiché ogni colonna
contiene uno ed un solo
valore e non ci sono Figura 8 - La tabella T_Order3 è in Prima Forma Normale.
gruppi di colonne
ripetute. Per attenersi alla 1FN è sufficiente aggiungere una colonna, OrderItem, modificando la
chiave primaria della tabella in una chiave composita formata da Order_Id e OrderItem.
E’ ora possibile costruire una semplice query (vedi Fig. 9) per determinare il numero di martelli
ordinati.

Figura 9 –Semplice query per determinare il numero totale di martelli ordinati, con T_Order3 in 1FN.

Seconda forma normale

Una tabella è in Seconda Forma Normale (2FN), se è in 1FN e ogni colonna non chiave è
totalmente dipendente dalla chiave primaria (completa).

In altri termini, le tabelle dovrebbero solamente memorizzare dati relativi ad una “cosa”, o “entità”,
e tali entità dovrebbero essere identificate univocamente dalla loro chiave primaria.

La tabella T_Order4 in Fig. 10 è una versione leggermente modificata della T_Order3. Come la
T_Order3, T_Order4 è in 1FN: ogni colonna è atomica e non ci sono gruppi ripetuti di
informazioni.

Figura 10 – T_Order4 è in 1FN

Per determinare se T_Order4 è in 2FN, occorre verificarne la chiave primaria.

Come visualizzato in Fig. 10, la chiave primaria di T_Order4 è composta da Order_Id e


Order_Item.
Affinché T_Order4 sia in 2FN, ogni sua colonna non-chiave (cioè ogni colonna diversa da Order_Id
e Order_Item) deve essere totalmente dipendente da Order_Id e Order_Item.

In altre parole, il valore di Order_Id e Order_Item per una data riga determina il valore di ogni altra
colonna nella tabella? La risposta è no!

Questo perché, dato un Order_Id, è possibile conoscere codice cliente (Customer_Id) e data ordine
(Order_Date), senza dover conoscere anche il valore di Order_Item. Infatti, essendo codice cliente e
data ordine ripetuti per ciascun Order_Id, possiamo dire che le due colonne Customer_Id e
Order_Date dipendono solo da Order_Id e non dall’intera chiave primaria (Order_Id, Order_Item).
Possiamo quindi concludere che la tabella T_Order4 non è in 2FN.

Per essere in 2FN, T_Order4 deve essere suddivisa in due tabelle.

Data una tabella non-normalizzata, il processo di suddivisione nelle sue parti normalizzate è
chiamato decomposizione. Dovremo quindi sottoporre la tabella T_Order4 ad un processo di
decomposizione.

Poiché T_Order4 ha una chiave composita, il processo di decomposizione è immediato: è


sufficiente associare le colonne che si riferiscono ad un ordine (individuato da Order_Id) in una
tabella e le colonne che si riferiscono ad un articolo (individuato da Order_Item) in un’altra tabella.
Le due tabelle T_Order e T_OrderDetails ottenute dalla decomposizione di T_Order4 sono mostrate
in Fig. 11.

Figura 11 – T_Order e T_OrderDetails sono in 2FN.

Affinché la decomposizione delle tabelle consenta la successiva ricomposizione dei dati tramite
query, le tabelle risultanti dalla decomposizione devono essere associate mediante una chiave
esterna.
Nel nostro esempio, T_OrderDetails è associata a T_Order mediante la chiave esterna Order_Id,
associazione utilizzabile agevolmente nelle condizioni di join (vedi clausola WHERE in Fig. 11).

Nota: quando si normalizza, non si elimina nessuna informazione. E’ un aspetto da non trascurare!
Infatti, per questa forma di decomposizione denominata senza-perdita, nessuna informazione è
sacrificata a beneficio del processo di normalizzazione.

Terza forma normale

Una tabella è in Terza Forma Normale (3FN), se è in 2FN e se tutte le colonne non-chiave
sono mutuamente indipendenti.

Un esempio banale di dipendenza è una colonna calcolata. Per esempio, se una tabella contenesse le
colonne Quantity e PerItemCost, si potrebbe aggiungere una colonna TotalCost in cui memorizzare
il risultato del calcolo Quantity*PerItemCost, Tuttavia, a causa dell’introduzione di questa
dipendenza, la tabella non sarebbe più in 3FN (ammesso che prima lo fosse!).

La soluzione migliore in questi casi è quindi lasciare le colonne calcolate fuori dalle tabelle ed
eseguire il calcolo in una query. In tal modo si risparmia spazio nella base dati e si evita
l’aggiornamento delle colonne calcolate (nel nostro esempio la colonna TotalCost) ogni qualvolta i
valori nelle colonne che contengono le variabili (nel nostro esempio Quantity e PerItemCost) sono
modificati.

Un esempio meno banale di dipendenza è visibile nella tabella T_OrderDetails di Fig. 11, che
mostra come in una tabella possano anche esistere dipendenze che non siano il mero risultato di un
calcolo.

La tabella T_OrderDetails è in 2FN perché tutte le sue colonne non-chiave (Quantity, Product_Id e
Product_Desc) sono totalmente dipendenti dalla chiave primaria. Quindi, dati un Order_Id ed un
Order_Item, si conoscono i valori di Quantity, Product_Id e Product_Desc.
Sfortunatamente, T_OrderDetails contiene anche una dipendenza fra due delle sue colonne non-
chiave, Product_Id e Product_Desc, il che impedisce a T_OrderDetails di essere in 3FN.

Ci troviamo quindi di fronte ad una ridondanza che, come evidenziato nel seguito, è causa di
problemi quando si aggiungono, aggiornano o cancellano righe.

Supponiamo per esempio che nella tabella T_OrderDetails occorra aggiungere 100 righe, ognuna
delle quali si riferisce all’acquisto di cacciaviti (screwdrivers). Occorrerebbe ripetere 100 volte, una
per ogni riga, l’inserimento dei valori Product_Id=2 e Product_Desc=screwdriver!

In modo simile, se decidessimo di cambiare la descrizione dell’articolo con Product_Id=2 in un


momento successivo all’inserimento dei dati, dovremmo aggiornare tutte e 100 le righe.

Un altro problema sorgerebbe se, alla fine del 2007, si desiderasse cancellare tutte le righe relative
ad acquisti di cacciaviti (screwdrivers). Una volta cancellate tutte le righe, non saremmo più in
grado di dire a cosa si riferisce un prodotto avente Product_Id =2.

E’ possibile rimediare ad ognuna di tali anomalie normalizzando ulteriormente la base dati, in modo
da portarla in 3FN.
Nota Un’anomalia è semplicemente un errore di inconsistenza nella base dati. Quando si crea una
base dati, occorre sempre ricordare che un disegno poco accurato comporta il rischio di introdurre
numerose anomalie, con conseguenti inefficienze e difficoltà di gestione.

Classifichiamo le anomalie come segue:

1. Inserimento — un’anomalia che occorre durante l’inserimento di una riga. Per esempio,
l’inserimento di una nuova riga potrebbe causare un errore in un totale calcolato,
memorizzato in un’altra tabella.

2. Cancellazione — un’anomalia che occorre durante la cancellazione di una riga. Per


esempio, la cancellazione di una riga dalla base dati potrebbe cancellare più informazioni di
quelle che si volevano effettivamente eliminare.

3. Aggiornamento — un’anomalia che occorre durante l’aggiornamento di una riga. Per


esempio, l’aggiornamento della descrizione di un articolo in una base dati di inventario
potrebbe richiedere la modifica di migliaia di righe.

Per raggiungere la 3FN, la tabella T_OrderDetails può essere ulteriormente decomposta spostando
la dipendenza Product_Id-Product_Desc in una tabella di lookup, come mostrato in Figura 12.

Questo modifica comporta quindi la modifica della T_OrderDetails, da cui sarà rimossa la colonna
Product_Desc, e la creazione della tabella di lookup T_Product, composta dalle due colonne
Product_Id e Product_Desc.

Nel seguito chiameremo T_OrderDetails1 la tabella T_OrderDetails modificata. Nella nuova tabella
T_Product la colonna Product_Id sarà la chiave primaria, mentre nella tabella T_OrderDetails1 la
colonna Product_Id sarà una chiave esterna riferita alla colonna Product_Id in T_Product.

Le modifiche introdotte consentono la successiva ricomposizione dei dati tramite query, in maniera
analoga a quanto visto in precedenza per la 2FN.

Figura 12 – T_OrderDetails1 e T_Product sono in 3FN.


Altre forme normali

In seguito alla definizione da parte di Codd dell’insieme originale di forme normali, fu scoperto che
la 3FN, così come originariamente definita, aveva alcune inadeguatezze. Ciò condusse a forme
normali di ordine più elevato, includendo la Boyce/Codd, la 4FN e la 5FN, delle quali però non ci
occuperemo e per le quali si rimanda ai testi elencati in Appendice13.

Inoltre, vi sono alcuni punti che vale la pena di notare:

 Ogni forma normale è un sovrainsieme di tutte le forme normali di ordine inferiore.


Perciò, se la vostra base dati è in 3FN, per definizione è anche in 1FN e 2FN.
 Se avete normalizzato la vostra base dati in 3FN, probabilmente avete raggiunto
anche la forma normale di Boyce/Codd (e forse anche la 4FN e la 5FN).
 I principi che guidano la progettazione di basi dati non sono altro che “buon senso
formalizzato”. La progettazione di basi dati è più arte che scienza.

L’ultimo punto deve essere enfatizzato. Se è relativamente facile comprendere ed applicare le


soluzioni negli esempi precedenti, il processo diventa più difficile quando si è posti di fronte ad un
reale problema di business, o qualunque altro scenario del mondo reale, che deve essere
computerizzato e dimensionato tenendo conto dei vincoli del sistema di elaborazione che abbiamo a
disposizione.

Un opportuno approccio è discusso nel seguito di questo documento, ma prima occorrerà affrontare
l’argomento delle regole di integrità.

13
Si veda in particolare ‘[3] The Relational Model, Version 2. EF Codd. Addison Wesley’.
Regole d’integrità

Il modello relazionale definisce diverse regole d’integrità che, pur non essendo parte della
definizione delle Forme Normali, sono una parte necessaria di qualsiasi base dati.

Classifichiamo le regole d’integrità in due tipi fondamentali:

 Generali
 Specifiche della base dati

Regole d’integrità generali

Il modello relazionale specifica due regole d’integrità generali14:

 integrità di entità
 integrità referenziale

Integrità di entità

L’integrità di entità dice semplicemente che le chiavi primarie non possono contenere valori nulli.

La regola si applica sia a chiavi semplici sia a chiavi composite. Per le chiavi composite, nessuna
colonna che compone la chiave può contenere valori nulli.

La ragione della presenza di questa regola dovrebbe essere ovvia: non si può identificare
univocamente una riga in una tabella se la chiave primaria contiene valori nulli.

Integrità referenziale

L’integrità referenziale impone che una base dati non debba contenere chiavi esterne che non
abbiano corrispondenza nella tabella referenziata. Ciò implica che:

 Una riga può essere aggiunta ad una tabella con una chiave esterna solo se, nella nuova riga,
il valore della chiave esterna esiste nella tabella referenziata.

 Se il valore in una tabella che è referenziata da una chiave esterna è modificato (o l’intera
riga è cancellata), le righe nella tabella con la chiave esterna non devono rimanere “orfane”
del loro riferimento.

La gestione di tali implicazioni è demandata al DBMS. L’impostazione delle modalità di gestione è


tuttavia compito di chi disegna la base dati ed è eseguibile tramite istruzioni DDL con opzioni
specifiche del DBMS in uso.

L’effettivo utilizzo e la definizione dei vincoli di integrità può variare, ma il concetto di integrità
referenziale e le opzioni possibili dovrebbero essere gli stessi per tutti i DBMS.

14
Con ‘generali’ si intende che tali regole si applicano a tutti i database.
I vincoli sono in genere definiti mediante un’istruzione ALTER TABLE, le cui opzioni possono
però differire a seconda dell’implementazione del linguaggio SQL supportata dal DBMS che si sta
utilizzando.

Ad esempio, quando è cancellata una riga da


una tabella referenziata, possiamo impostare in
Oracle15 le seguenti opzioni:

1. Nessuna azione. L’aggiornamento o la


cancellazione di una riga da una tabella
referenziata non produce alcuna azione
da parte del DBMS.

2. In cascata. L’aggiornamento o la
cancellazione di una riga in una tabella
referenziata produce da parte del
DBMS l’aggiornamento o
l’eliminazione, in tutte le tabelle
dipendenti, di tutte le righe contenenti
il riferimento alla riga cancellata dalla
tabella referenziata.

3. Default o Annullamento. La
cancellazione di una riga in una tabella
referenziata produce da parte del
DBMS, in tutte le tabelle dipendenti,
Figura 13 - Opzioni supportate in Oracle in cancellazione,
l’impostazione ad un valore di Default quando è eliminata una riga da una tabella referenziata.
o a Null dei valori della chiave esterna
in tutte le righe contenenti il riferimento alla riga cancellata dalla tabella referenziata. Tali
opzioni possono essere implementate creando un trigger (vedi cenni sui trigger Oracle nel
paragrafo successivo) sulla tabella riferita dalla chiave esterna e l’opzione di annullamento
risulta valida solo se la chiave esterna è opzionale.

Regole d’integrità specifiche della base dati

Tutte le regole che non ricadono nell’integrità di entità o nell’integrità referenziale sono specifiche
della base dati e quindi dipendono dal ‘business’, ossia dal sistema del mondo reale modellato dalla
base dati stessa. Nonostante la specificità di tali ‘regole di business’, sottolineiamo come la loro
presenza nella base dati sia tanto importante quanto le regole di integrità generali discusse nella
sezione precedente.

Senza la specifica ed il consolidamento delle opportune regole di business, nel database potrebbero
essere inseriti dei dati errati.

Per esempio, una attività commerciale del tipo ‘pizza a domicilio’ potrebbe avere le seguenti regole,
opportunamente modellate nella base dati:

 La data ordine non può essere inferiore alla data di inizio attività.
 L’ora dell’ordinazione e l’ora di consegna devono essere entro gli orari di apertura e
chiusura del negozio.

15
Altri DBMS potrebbero fornire opzioni differenti, in modalità differenti.
 L’ora di consegna deve essere successiva o uguale all’ora dell’ordinazione.
 Non possono essere accettate ordinazioni per pizze non presenti nel menu del giorno.
 Non possono essere accettate ordinazioni al di fuori di un certo raggio d’azione – es.
utilizzando il codice di avviamento postale per determinare l’area entro la quale possono
essere effettuate le consegne in tempo accettabile.
 Il quantitativo ordinato non può mai essere inferiore a 1 e superiore a 50.
 Eventuali sconti non possono mai essere inferiori all’1% e superiori al 30%.

Se i valori di una colonna devono essere


compresi in un determinato intervallo o
devono soddisfare particolari condizioni, in
Oracle si può ricorrere ad un CHECK
constraint (vincolo di controllo) per
specificare un’espressione che dev’essere
sempre vera per ogni riga della tabella.
CREATE TABLE ALB.T_ORDER_PIZZA
Nel nostro esempio, come mostrato in Fig. 14, (
si può impedire l’inserimento nella tabella ORDER_ID NUMBER NOT NULL,
ORDER_DATE DATE NOT NULL,
T_ORDER_PIZZA di date anteriori alla data CHECK (ORDER_DATE >= TO_DATE('31/12/2006',
di inizio attività mediante il vincolo di 'DD/MM/YYYY')),
CUSTOMER_ID NUMBER NOT NULL,
controllo: ORDER_TAKER_ID NUMBER NOT NULL,
DELIVERY_DATE DATE NOT NULL,
DELIVERY_TIME DATE NOT NULL,
CHECK (ORDER_DATE >= TO_DATE('31/12/2006',
PAYMENT_METHOD VARCHAR2(64) NOT NULL,
'DD/MM/YYYY'))
NOTES CLOB
)
definito a livello di colonna per /
ORDER_DATE16. ALTER TABLE ALB.T_ORDER_PIZZA
ADD CONSTRAINT T_ORDER_PIZZA_KEY PRIMARY KEY
(ORDER_ID)
Poiché un vincolo di controllo a livello di /
colonna è soggetto ad alcune restrizioni17, si
può usare in alternativa la forma del vincolo di Figura 14 – Vincolo di controllo a livello di colonna
tabella.

Sempre nel nostro esempio, invece di verificare che la data ordine sia anteriore alla data di inizio
attività, sarebbe più opportuno assicurarsi che la data inserita sia compresa tra la data di inizio
attività e la data corrente.

In Oracle sia i vincoli di controllo a livello di colonna, sia i vincoli di tabella pongono restrizioni18
che ne impediscono l’utilizzo per risolvere il nostro problema.

E’ tuttavia possibile ricorrere ai trigger19, per migliorare l’integrità referenziale dichiarativa, per
imporre regole complesse legate al sistema del mondo reale che si sta modellando o per effettuare
revisioni sulle modifiche ai dati.

16
Supponendo che la data di inizio attività sia il 31/12/2006.
17
Es. Non può fare riferimento a valori in altre righe.
18
Nei vincoli di controllo non è consentito usare le pseudocolonne SysDate, UID, User, Userenv, Currval, Nextval,
Level o RowNum.
19
Un trigger definisce un’azione che il DBMS deve intraprendere quando si verifica un determinato evento definito per
la base dati.
La trattazione delle modalità di utilizzo dei trigger in Oracle esula dallo scopo di questo documento.
Si rimanda ai testi in Appendice20 per gli approfondimenti del caso.

Nota I vincoli di colonna ed i trigger possono aggiungere integrità referenziale, tuttavia non
possono essere utilizzati in sostituzione di questa. Quando in un’applicazione si impongono regole
legate al sistema che si sta modellando, per prima cosa è necessario affidarsi all’integrità
referenziale dichiarativa disponibile in Oracle; quindi si potranno utilizzare vincoli di colonna e
trigger per imporre regole che non possono essere codificate attraverso l’integrità referenziale.

20
Cfg. [5] Oracle 9i: The Complete Reference. K.Loney, G.Kosh and the experts at TUSC. McGraw-Hill/Osborne.
Un approccio pratico alla progettazione
Se è vero che un database progettato in modo appropriato dovrebbe seguire le forme normali ed il
modello relazionale, il reale obiettivo da raggiungere è un disegno della base dati che rifletta il
sistema del mondo reale da modellare.

Per perseguire tale scopo, la teoria delle basi dati relazionali ci dice cosa non dobbiamo fare, ma
non da dove partire, come far evolvere il progetto e quali compromessi eventualmente accettare per
ottenere il nostro scopo.

Diventa perciò di primaria importanza la comprensione del sistema da modellare e dello scenario in
cui opera il sistema stesso. Una base dati ben congegnata, sia per il modello logico, sia per il
modello fisico, richiede comprensione approfondita del sistema da modellare, nonché tempo ed
esperienza per trasferire efficacemente all’interno del DBMS il modello del sistema stesso.

Per ottimizzare le performance o per soddisfare al meglio i requisiti degli utenti finali, il nostro
disegno potrebbe dover contemplare un certo grado di de-normalizzazione.

E’ comprensibile che una simile affermazione desti sorpresa in chi legge. Per affrontare al meglio
anche questa circostanza, nel seguito sono elencati alcuni criteri da utilizzare, onde evitare di
trovarsi successivamente in difficoltà a causa di scelte fatte in modo poco convinto o addirittura
inconsapevole.
Modello logico

Non essere frettolosi nelle scelte è fondamentale, onde evitare la gestione a posteriori di alterazioni
dello schema della basi dati, le quali non sempre saranno possibili.

Per evitare tali ‘trappole’, o perlomeno ridurre i rischi di incapparvici, nel seguito è proposto un
approccio in 20 passi, come linea guida da seguire per la creazione del modello logico.

1. Dedicate un (bel) po’ di tempo all’apprendimento del sistema che si sta tentando di
modellare. Tipicamente questo comporterà uno o più incontri con chi dovrà utilizzare la
base dati, per porre loro tutte le domande necessarie alla comprensione del sistema.

2. Su carta, scrivete un descrizione sintetica del sistema, che sia immediatamente


comprensibile da chiunque. Per esempio qualcosa del genere: <<Questo è un sistema di
gestione degli ordini. Sarà usato per acquisire e memorizzare gli ordini dei clienti e per
tracciare gli ordini stessi per ragioni gestionali e di inventario.>>. Inoltre, elencate i requisiti
del sistema ed i relativi casi d’uso. L’elenco così ottenuto vi guiderà nella creazione dello
schema della basi dati e nella definizione dei vincoli associati alle regole di business. Per
esempio creare una lista che includa voci del tipo: <<Deve essere possibile tracciare
l’indirizzo di posta elettronica del cliente per il successivo invio di informazioni tramite
email>>.

3. Abbozzate su carta il disegno dei form per l’inserimento dati, siano essi Web form, Oracle
Developer o form applicativi di altro genere. Se facendolo vi vengono in mente delle regole
o delle idee che possono influenzare il disegno delle tabelle, aggiungetele alla lista dei
requisiti citata nel passo precedente.
Lo specifico approccio seguito sarà guidato dallo stato del sistema esistente.

o Se il sistema non è mai stato computerizzato, partite dai moduli21 cartacei ed


abbozzate il disegno delle tabelle basandovi su tali moduli. E’ molto probabile che il
risultato così ottenuto sarà non-normalizzato.

o Se la base dati sarà convertita da un precedente sistema computerizzato, usate le sue


tabelle (o altre sorgenti dati, es. fogli Excel, file di testo, etc.) esistenti come punto di
partenza.
Ricordate, comunque, che è molto probabile ritrovarsi con uno schema esistente non-
normalizzato e che sarà molto più semplice normalizzare il vostro database adesso
piuttosto che successivamente. Stampate su carta lo schema esistente, tabella per
tabella, insieme ai form per l’inserimento dati.

o Se state partendo da zero (es. progetto riguardante un’attività commerciale che sta
partendo ora), abbozzate sulla carta quali form prevedete di utilizzare
nell’applicazione.

4. Sulla base dei form creati nel passo 3, abbozzate le vostre tabelle sulla carta.
Se siete a vostro agio con la normalizzazione, provate a normalizzare subito (non siate
pigri!), tenendo a mente i dettami della teoria mentre create le vostre tabelle, ricordando
soprattutto che ogni tabella dovrebbe descrivere una singola entità.
Se proprio non volete normalizzare le tabelle in questa fase, potete iniziare creando un'unica,

21
I termini ‘modulo’ e ‘form’ sono usati qui in modo equivalente, anche se il termine ‘modulo’ è più intuitivamente
riconducibile ai moduli cartacei, mentre ‘form’ è più intuitivamente riconducibile ai moduli applicativi (es. Web form,
Oracle Developer form, Access form, o form per altre tecnologie applicative).
grande tabella non-normalizzata per ciascun form, che provvederete a normalizzare
successivamente.

5. Guardate ai report esistenti, siano essi in formato cartaceo o elettronico.


o Se state partendo da zero, abbozzate sulla carta i tipi di report che prevedete di avere.
o Nei sistemi esistenti è probabile che vi siano report chiave mancanti22. Create adesso
su carta i report mancanti.

6. Prendete i report abbozzati nel passo 5 ed assicuratevi che le tabelle create nel passo 4
includano tutti i dati. Se vi accorgete che vi sono dati mancanti, aggiungeteli alle tabelle
esistenti o createne di nuove.

7. Su carta, aggiungete diverse righe ad ognuna delle tabelle abbozzate. Usate dati il più
possibile reali.

8. Iniziate il processo di normalizzazione. Dapprima identificate le chiavi candidate per ogni


tabella e, tra le chiavi candidate, scegliete la chiave primaria. Ricordate di scegliere una
chiave primaria che sia minimale, semplice, stabile e familiare. Ogni tabella deve avere una
chiave primaria! Assicuratevi che la chiave primaria garantisca l’assenza presente e futura di
duplicati.

9. Individuate le chiavi esterne, aggiungendole alle relative tabelle ove necessario. Disegnate le
relazioni tra le tabelle, indicando se sono uno-a-uno o uno-a-molti. Create le opportune
tabelle di collegamento se sono molti-a-molti.

10. Determinate se le tabelle sono in 1FN.


o Sono atomici tutti i campi?
o Ci sono gruppi ripetuti?
Se necessario, decomponete le tabelle per ridurle in 1FN.

11. Determinate se le tabelle sono in 2FN.


o Ogni tabella descrive una singola entità?
o Tutte le colonne non-chiave sono completamente dipendenti dalla chiave primaria?
In altri termini, il valore della chiave primaria determina il valore di tutte le altre
colonne in ogni tabella?
Se necessario, decomponete le tabelle per ridurle in 2FN. Se una tabella ha una chiave
primaria composita, la decomposizione dovrebbe, in generale, essere eseguita suddividendo
la chiave negli elementi che la compongono e mettendo tutte le colonne pertinenti ciascun
componente della chiave primaria nella propria tabella.

12. Determinate se le tabelle sono in 3FN.


o Ci sono colonne calcolate?
o Ci sono colonne non-chiave che sono mutuamente dipendenti?
Rimuovete le colonne calcolate. Eliminate le colonne mutuamente dipendenti
suddividendole in opportune tabelle di lookup.

13. Rifinite le relazioni tra le tabelle ottenute al passo 12.

14. Preparate gli script DDL (cfg. fig. 14) per la creazione dello schema del database. Eseguite
gli script ed aggiungete valori di esempio alle tabelle così create.

22
Ciò è comprensibile: se tali sistemi sono soggetti a modifica è perché non rispondono ai nuovi requisiti degli utenti,
quindi l’aggiunta di nuove tabelle e moduli di inserimento dati non può che avere come conseguenza l’aggiunta di
nuovi report.
15. Create le versioni preliminari delle query e degli eventuali packages PL/SQL23, dei form e
dei report. Mentre create tali oggetti, migliorate il vostro disegno ove necessario nel caso si
manifestassero lacune progettuali,.

16. Ritornate dagli utenti finali. Chiedete loro di valutare i vostri form e report.
o Corrispondono ai requisiti degli utenti?
Se così non fosse, raffinate il vostro disegno. Ricordatevi di ri-normalizzare ove necessario
(passi 8-12).

17. Tornate al disegno delle tabelle e aggiungete le ‘regole di business’ ove necessario.

18. Create le versioni finali delle query e degli eventuali packages PL/SQL, dei form e dei
report. Sviluppate l’applicazione. Raffinate il disegno ove necessario.

19. Chiedete agli utenti di testare il sistema. Raffinate il disegno ove necessario.

20. Consegnate il sistema finale.

Questa lista chiaramente non è esaustiva ed è ben lungi dal ricoprire ogni sfaccettatura del processo
di disegno. Serve solo ad incoraggiarvi a seguire una metodologia nella definizione pratica del
vostro progetto.

23
Linguaggio di programmazione ‘embedded’, proprietario di Oracle. Altri DBMS fanno uso di linguaggi differenti,
altri ancora potrebbero non avere alcun linguaggio di programmazione
Modello fisico

Partendo dal disegno iniziale del modello logico, è necessario analizzare un grande numero di
parametri (vedi Fig.15) al fine di ottenere un modello fisico corretto.

Notare l’espressione ‘un modello’, non ‘il modello’.


Questo per sottolineare come, al pari di altri temi
riguardanti la progettazione di database, non c’è una
verità assoluta da assumere ciecamente per la
definizione del modello fisico.

Si evidenziano nel seguito i punti principali:

1. Il volume atteso delle tabelle, le


caratteristiche hardware –velocità CPU,
dimensione della memoria, numero di dischi Figura 15 – Parametri che influenzano il modello fisico
e spazio corrispondente–, l’architettura – client/server o three-tier–, la larghezza di banda ed
il sistema operativo sono determinanti.

2. I requisiti utente sono un altro argomento da considerare. A seconda del tempo di risposta,
dell’interfaccia utente, della frequenza d’uso dei form, ne risultano influenzati gli oggetti
che possono essere usati in Oracle in accordo
con le aspettative dell’utente..

3. A seconda della versione di Oracle in uso,


alcuni elementi possono o non possono esistere.

Altri punti possono riguardare:

 Indici – Gli indici sono strutture di database


memorizzate separatamente dalle tabelle da cui
dipendono. Gli indici non influenzano il Figura 16 – Uso degli indici nelle basi dati
modello della base dati: in un database
relazionale è possibile richiedere qualsiasi colonna, indipendentemente dall’esistenza di un
indice su quella colonna.
Gli indici sono utilizzati per due ragioni
(vedi Fig.16):

o Per velocizzare le query

o Per assicurare l’unicità, quando essa è


richiesta dal modello

 Viste – Una vista è una finestra sulla base


dati (vedi Fig.17). E’ definita da una
SELECT a cui è attribuito un nome, con cui
la select stessa è memorizzata nella base dati.
Figura 17 – Uso delle viste nelle basi dati
Perciò una vista non ha dati propri – si
appoggia sulle informazioni provenienti dalle
tabelle sottostanti. Le viste sono utilizzate per:
o Restrizione accessi: usare una vista è uno dei possibili modi per nascondere colonne
e righe delle tabelle su cui la vista stessa è basata.

o Presentazione dati: Una vista può essere usata per presentare dati in modo più
familiare e comprensibile per gli utenti finali. Per esempio, una vista può presentare
dati definiti a partire da informazioni elementari memorizzati in varie tabelle.

o Isolamento delle applicazioni dalle strutture dati: le applicazioni possono basarsi


sulle viste piuttosto che sulle tabelle, nel caso in cui vi sia il rischio che le strutture
possano cambiare. Usando una vista,
in caso di modifica delle tabelle
sottostanti l’applicazione non
richiederà manutenzione, a patto che la
vista stessa non sia modificata.

o Mascheramento di query complesse e


conseguente semplificazione dei
comandi: una vista può nascondere la
complessità della struttura dati
sottostante, consentendo agli utenti di
creare query su tabelle multiple senza
dover conoscere le modalità di join fra le Figura 18 – Partizionamento di tabelle
tabelle.

o Semplificazione dei comandi usati dagli utenti finali.

 Partizionamento di tabelle – Oracle consente di effettuare un partizionamento (vedi Fig.18)


per risolvere problemi di performance e di amministrazione su tabelle con un numero di
righe molto ampio.

 Design distribuito – E’ caratterizzato dall’esistenza di molteplici database fisici, locati in


nodi differenti, che però appaiono all’utente con un singolo ‘database logico’ (vedi Fig.19).

Figura 19 – Database fisici distribuiti, visti come un unico database logico

Una trattazione dettagliata degli argomenti legati alla progettazione fisica del database esula dallo
scopo di questo documento. Si rimanda ai testi in Appendice24 per gli approfondimenti del caso.

24
Cfg. [5] Oracle 9i: The Complete Reference. K.Loney, G.Kosh and the experts at TUSC. McGraw-Hill/Osborne - [6]
Data Modeling and Relational Database Design. J.Speelpenning, P.Daux, J.Gallus. Oracle Corporation.
Violare le regole: quando de-normalizzare

A volte è necessario violare le regole di normalizzazione e creare un database che è deliberatamente


meno normalizzato di quanto dovrebbe essere.

Spesso ciò è motivato da ragioni di performance o da una richiesta espressa dagli utenti finali.
Se una tale scelta non farà esultare i puristi della progettazione di basi dati, il vostro obiettivo
rimane quello di soddisfare gli utenti, per cui in determinate situazioni una soluzione di
compromesso potrebbe essere giustificata.

Qualora decideste di violare le regole e accettaste di de-normalizzare la vostra base dati, è


importante che osserviate le linee guida seguenti:

 Se violate le regole intenzionalmente, fatelo con delle buone ragioni (non de-normalizzate
solo perché un vincolo su una tabella vi impedisce un inserimento o una cancellazione!)

 Siate pienamente consapevoli dei pro e contro che la vostra decisione comporta

 Documentate accuratamente la vostra decisione

 Create i necessari aggiustamenti nel codice dell’applicazione associata alla vostra base dati,
al fine di evitare anomalie, documentando accuratamente le modifiche apportate.

E’ opportuno soffermarsi sull’ultimo punto. Nella maggior parte dei casi, quando si de-normalizza,
nell’applicazione è richiesto del codice addizionale per evitare anomalie negli inserimenti, negli
aggiornamenti e nelle cancellazioni, codice che non sarebbe necessario con un disegno
maggiormente accurato.

Per esempio, qualora decideste di memorizzare il risultato di un calcolo in una tabella, ai form
contenenti i dati sui quali è basato il calcolo dovrà essere associato/aggiunto il codice per la
gestione appropriata degli eventi di modifica: la modifica di uno o più valori nei form associati
dovrà causare l’aggiornamento del corrispondente valore, calcolato nella tabella.

Se, per ragioni di performance, a priori decidete di non normalizzare o state de-normalizzando, non
dovete assumere che l’approccio migliore sia sempre e comunque questo. L’approccio corretto è
quello di normalizzare sempre e completamente il database (portandolo in 3FN o altra forma
superiore) e quindi de-normalizzare solo quando diventa necessario.

Se state de-normalizzando perché i vostri utenti ve lo hanno chiesto, prima di farlo cercate di
comprendere a fondo le motivazioni della richiesta. Gli utenti ricercano la massima semplificazione
del loro lavoro e spesso sono solo preoccupati dai possibili problemi causati dai vincoli di integrità
nella fase di inserimento dei dati. La gestione dei vincoli e la massima semplificazione
nell’inserimento dei dati potrà essere ottenuta, nella quasi totalità dei casi, disegnando correttamente
i form e le query SQL da associare ai form stessi, senza per questo dover de-normalizzare il
database.
Seguono alcuni scenari che potrebbero giustificare la violazione delle regole di normalizzazione:

 Decidete di memorizzare una colonna calcolata e indicizzata -es. ‘SOUNDEX’ in


‘T_CUSTOMER’- per migliorare le performance. La colonna SOUNDEX dovrà
contenere la ‘pronuncia’ del cognome in LAST_NAME: memorizzare il valore calcolato
all’atto dell’inserimento del cognome ed indicizzare la colonna, piuttosto che
determinare il valore ad ogni query, comporta un significativo incremento di
performance, specie nelle ricerche, quindi decidete di violare la 3FN (SOUNDEX
dipende da LAST_NAME). Dovrete associare/aggiungere ai form il codice per la
gestione dell’evento richiesto per il calcolo e la memorizzazione del risultato nella
colonna SOUNDEX. Inoltre, per evitare anomalie di aggiornamento, dovrete assicurare
che la colonna SOUNDEX non possa essere aggiornata dagli utenti finali e che sia
aggiornata applicativamente tutte le volte che LAST_NAME è modificata.

 Per migliorare le performance, decidete di creare una colonna TOTAL_ORDER_COST


che contiene la somma dei costi di ciascun articolo in T_ORDER. Questo viola la 2NF
perché TOTAL_ORDER_COST è dipendente dalla chiave primaria in
T_ORDER_DETAILS, non da quella in T_ORDER. TOTAL_ORDER_COST è
calcolato mediante codice applicativo associato/aggiunto ai form, sommando la colonna
TOTAL_COST per ogni articolo. Poiché si creano spesso report che riportano il costo
totale dell’ordine, ma non il costo del singolo articolo, avete violato la 2FN per evitare di
mettere in join le due tabelle ogni volta che il report deve essere rigenerato. Come
nell’ultimo esempio, dovrete assicurare che non vi siano anomalie in fase di
aggiornamento. Ogni volta che è inserito, aggiornato o eliminato un record in
T_ORDER_DETAILS, si dovrà infatti aggiornare T_ORDER, o l’informazione in essa
contenuta risulterà non corretta.

 Decidete di includere una colonna, SALES_PERSON, in T_INVOICE. Anche se


SALES_ID è già inclusa in T_INVOICE. Questo viola la 3FN perché le due colonne
non-chiave sono mutuamente dipendenti, ma migliora significativamente le performance
per determinati report generati frequentemente. Ancora una volta, la violazione e
introdotta per evitare una join, tra T_INVOICE e T_EMPLOYEE, ma introduce
ridondanze e crea il rischio di anomalie in aggiornamento.

Si tratta di esempi relativi a problemi che in Oracle possono essere agevolmente risolti usando un
TRIGGER, ma che in altri DBMS25 rappresentano l’unica soluzione.

Potrete aggiungere altri esempi sulla base della vostra esperienza.

25
es. in MS-Access.
Sommario
Questo documento ha descritto i fondamenti della progettazione delle basi dati, sintetizzati nel
seguito:

 Il modello relazionale fu creato da E.F. Codd nel 1969 e si fonda sulla teoria degli insiemi e
sulla logica dei predicati.

 Una base dati progettata in accordo con il modello relazionale sarà efficiente, dal
funzionamento prevedibile, performante, auto-documentata e facile da modificare.

 Ogni tabella deve avere una chiave primaria, che identifica univocamente le righe nella
tabella stessa.

 Le chiavi esterne sono colonne usate come riferimento a chiavi primarie in un’altra tabella.

 Si possono definire tre tipi di relazioni tra tabelle in un database relazionale: uno-a-uno,
uno-a-molti, molti-a-molti. Le relazioni molti-a-molti richiedono una tabella aggiuntiva di
collegamento.

 La normalizzazione è il processo di semplificazione del disegno di una base dati, al fine di


ottenere una struttura ottimale.

 Una base dati ben disegnata è tale perché aderisce alle cosiddette ‘Forme Normali’.

 L’integrità di entità è una regola che vieta che le colonne associate alle chiavi primarie
contengano valori nulli.

 L’integrità referenziale è una regola che impone che la base dati non contenga chiavi esterne
orfane delle chiavi primarie a cui si riferiscono.

 Così come le regole di integrità, i vincoli, o ‘regole di business’, costituiscono un elemento


portante dell’integrità di una base dati.

 Una base dati ben congegnata richiede impegno e tempo per il suo concepimento, la sua
realizzazione ed il suo affinamento.

 Occasionalmente, può essere ammesso un certo grado di de-normalizzazione della base dati
per ragioni di performance.

La progettazione della base dati è un elemento costitutivo del sistema informativo che vi accingete a
creare: se dedicherete il tempo necessario al disegno appropriato della base dati, sarete ricompensati
con solide fondamenta sulle quali potrete costruire il resto della vostra applicazione.
Appendice

Risorse

Segue una lista di testi estremamente validi sul modello relazionale e sul DBMS (Oracle) citato nel
documento:

[1] An Introduction to Database Systems. Vol I. CJ Date. Addison Wesley.


[2] Database Processing: Fundamentals, Design, and Implementation. David M
Kroenke. MacMillan.

[3] The Relational Model, Version 2. EF Codd. Addison Wesley.


[4] SQL and Relational Basics. Fabian Pascal. M&T Books.
[5] Oracle 9i: The Complete Reference. K.Loney, G.Kosh and the experts at
TUSC. McGraw-Hill/Osborne.
[6] Data Modeling and Relational Database Design. J.Speelpenning, P.Daux,
J.Gallus. Oracle Corporation.

Potrebbero piacerti anche