Nella fase di progettazione di una base di dati è possibile compiere numerosi errori la cui presenza può dar luogo a varie problematiche, tra cui per esempio:
- il rallentamento delle prestazioni;
- la ridondanza dei dati dovuta ad inutili duplicazioni;
- l'ambiguità nelle informazioni gestite;
- il malfunzionamenti nei meccanismi di relazione tra le tabelle;
- la scarsa affidabilità dovuta alla poca accuratezza dei dati:
- la scarsa protezione dell’integrità dei dati;
- la difficoltà nella lettura dei dati e della struttura delle tabelle.
Esistono fortunatamente degli accorgimenti che permettono di rendere più semplice ed efficace il lavoro di progettazione, in questo modo sarà possibile limitare i problemi e le lungaggini derivanti dalle necessità di aggiornamenti e correzioni.
Nel corso di questa breve trattazione verranno analizzati alcuni di questi accorgimenti sottolineandone le implicazioni pratiche.
Relazioni e quantità di tabelle e campi
La logica alla base dei database relazionali si fonda sul concetto che qualsiasi elemento debba rappresentare un’entità "atomica", quindi non ulteriormente scomponibile in altre entità, questa caratteristica è necessaria perché, nel momento in cui si fa riferimento ad un determinato dato, non deve sussistere alcun pericolo di ambiguità; ogni elemento di una relazione deve essere quindi distinguibile e riferito ad un unico oggetto, sia esso una chiave primaria, il nome di una tabella, il nome di un campo etc.
Ora, uno dei concetti più controversi tra quelli che regolano la progettazione di una base di dati, riguarda il fatto che risparmiando sul numero delle tabelle si ottengono sistemi di relazione meno complesse; in realtà, se da una parte un database meno articolato può risultare nell’immediato più leggibile, l’utilizzo di un’unica tabella può rendere la digitazione delle istruzioni SQL molto più complessa.
Quanto appena esposto si ricollega con il concetto di "normalizzazione", una insieme di metodi che permettono di suddividere le tabelle nei loro componenti univoci, in modo che ogni tabella rappresenti un unico elemento e i campi che la compongono riproducano, tramite attributi, la descrizione dell’elemento rappresentato dalla tabella.
A livello di linguaggio, la normalizzazione non rappresenta un limite, in un’istruzione SQL SELECT è infatti sempre presente una clausola FROM per indicare la tabella interessata da una query a cui è possibile associare una JOIN per relazionarsi ad una seconda tabella o a più tabelle. Vediamo, nella prossima pagina, un esempio.
Si ipotizzi di avere a disposizione una tabella sul modello della seguente:
| Id_cliente | Nome_cliente | Fattura1 | Fattura2 | Fattura3 | Fattura4 |
|---|---|---|---|---|---|
| 1 | Mattia Rossi | 212.50 | 314.70 | 430,65 | 524.89 |
| 2 | Paolo Bianchi | 577.44 |
Basta una prima osservazione per capire che ci si trova davanti ad una tabella mal strutturata; anche ammettendo che non si preveda di staccare più di quattro fatture per ogni cliente (cosa nella pratica molto improbabile), che senso avrebbe creare un campo per ogni fattura per non voler utilizzare più di una tabella? Inoltre, plausibilmente un buon numero di clienti saranno destinatari di meno di quattro fatture, in alcuni casi una sola, la tabella potrebbe quindi riempirsi velocemente di valori nulli.
Perché quindi non ricorrere a due tabelle separate, una destinata alla fatturazione e una ai clienti? Qui entra in gioco la normalizzazione, "clienti" e "fatturazione" sono infatti due entità in grado di rappresentare due concetti non ulteriormente scomponibili ma dotati di caratteristiche proprie; in ogni caso, le due tabelle potranno essere utilizzate per stabilire delle relazioni attraverso una chiave, come per esempio il campo Id_cliente
Per cui potremmo normalizzare la tabella proposta in precedenza suddividendola in due nuove tabelle:
| Id_cliente | Nome_cliente |
|---|---|
| 1 | Mattia Rossi |
| 2 | Paolo Bianchi |
| Id_fattura | Id_cliente | Pagamento |
|---|---|---|
| 1 | 1 | 212.50 |
| 2 | 1 | 314.70 |
| 3 | 2 | 577.44 |
| 4 | 1 | 524.89 |
| 5 | 1 | 524.89 |
Lo stesso tipo di procedura potrà essere adottata per migliorare la struttura dei campi all’interno di una tabella; riprendendo la tabella "clienti" proposta in precedenza, è facile notare come in essa sia presente un campo denominato Nome_cliente
Rossi
LIKE
SELECT Nome_cliente FROM clienti WHERE Nome_cliente LIKE ‘%Rossi’;
In linea generale è però possibile affermare che, per ottenere lo stesso risultato, un Database manager impiega meno tempo ad eseguire una query SELECT
WHERE
LIKE
Per cui la tabella clienti potrà essere riproposta nel modo seguente:
| Id_cliente | Nome_cliente | Cognome_cliente |
|---|---|---|
| 2 | Mattia | Rossi |
| Tabelle | Campi |
|---|---|
| Clienti | nome, cognome, telefono, indirizzo, email.. |
| Prodotti | nome, codice, modello, prezzo.. |
| Ordini | quantità, cliente, sconto, modalità di spedizione.. |