Esplora E-book
Categorie
Esplora Audiolibri
Categorie
Esplora Riviste
Categorie
Esplora Documenti
Categorie
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.
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.
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.
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:
Illustriamo tale principio con un esempio. Diciamo che un’azienda ha una tabella di clienti chiamata
T_Customer , visualizzata in Fig. 1.
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:
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.
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.
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
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
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.
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:
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.
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.
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.
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!
Figura 9 –Semplice query per determinare il numero totale di martelli ordinati, con T_Order3 in 1FN.
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.
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.
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.
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.
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!
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.
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.
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.
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.
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.
Generali
Specifiche della base dati
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.
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.
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.
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%.
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.
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 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.
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.
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.
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.
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.
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..
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.
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
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.
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
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:
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.
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.
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.
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: