< Home
Stampa

Chiavi

Sommario

Concetti fondamentali

Ripartiamo dal modello logico-relazionale di un database e rivediamone i concetti fondamentali. Essi sono:

  • la tabella: rappresenta l’insieme dei valori di una specifica entità. Esempio l’album, l’autore, ecc. Rappresenta un insieme di entità, non ordinate.
  • l’attributo: rappresenta una colonna della tabella. Ad esempio il titolo dell’album. Ogni attributo ha un dominio di validità, ovvero un insieme di valori possibili. Se è un intero, è l’insieme degli interi memorizzabili, se una stringa l’insieme delle combinazioni di caratteri, ecc.
  • il record: rappresenta una riga di una tabella, cioè una istanza dell’entità contenente valori specifici per quella entità. E’ una tupla di valori, dove ogni valore (cioè la cella corrispondente all’attributo di un record) viene chiamata “campo“.

I record di una tabella sono parte di un insieme, che da un punto di vista matematico significa che non possono esserci due record con tutti i valori identici, ovvero due tuple identiche.

Siccome non possono esserci due tuple identiche, è necessario attivare un meccanismo che ci consenta di distinguere due tuple tra loro. Questo meccanismo è la chiave primaria.

Chiave primaria

Per capire come definire una chiave primaria in una entità, introduciamo il concetto di superchiave.

La superchiave è un attributo, o gruppo di attributi, che permettono di identificare una entità da quegli attributi. Ad esempio per l’anagrafica di una persona potrebbe essere il codice fiscale, per un prodotto il suo codice EAN, per una azienda la partita IVA, e così via. Deve essere diversa per ogni tupla e deve essere non nulla.

Ipotizziamo di avere la seguente tabella:

MatricolaCodice fiscaleNomeCognomeEmail
726265RSSMRA01A01F205ZMarioRossimrossi@cipiaceinfo.it
726266BRNBNC02B42H501WBiancaBrunobbruno@cipiaceinfo.it
726267GVNNNL00C15F205YGiovanniNerigneri@cipiaceinfo.it
726268VRDLRA03D50L219XLauraVerdilverdi@cipiaceinfo.it

Questa tabella può avere come superchiave:

  • Matricola: ogni tupla ne ha una diversa
  • Codice Fiscale: ogni tupla ne ha una diversa
  • Email: ogni tupla ne ha una diversa (stesso dominio)
  • Matricola, CodiceFiscale: una gruppo di superchiavi è superchiave
  • CodiceFiscale, Email: idem
  • Email, Matricola: idem
  • Matricola, CodiceFiscale, Email: idem

Le superchiavi possono essere più di una e possono essere anche ridondanti.

Dalle superchiavi possiamo ricavare le chiavi minimali, cioè quelle chiavi composte dal numero minimo di attributi. Qui ad esempio:

  • Matricola: ogni tupla ne ha una diversa
  • Codice Fiscale: ogni tupla ne ha una diversa
  • Email: ogni tupla ne ha una diversa

Da queste ne scegliamo una, che diventa chiave primaria della nostra tabella. Essa sarà usata come identificativo nel RDBMS per identificare la tupla.

La chiave primaria può essere multipla come in questo esempio, dove la chiave primaria è data dall’insieme {Matricola, Corso}.

MatricolaCorsoDataVoto
726267INF-0112/6/202628
726267INF-0217/7/202627
726267MAT-012/9/202630

Chiave esterna

La chiave primaria è utile anche per risolvere un altro problema: identificare univocamente, quando andiamo a collegare un record di una tabella con il record di un’altra tabella. Non c’è infatti pericolo di ambiguità perché la chiave primaria è univoca.

Qui vediamo proprio un esempio che collega l’entità Studente con l’entità Esame

Scomposizione di una tabella (es. Excel)

Finora abbiamo visto un processo lineare di progettazione: dal testo che descrive una realtà di riferimento andiamo a creare un modello concettuale e da questo il modello logico relazionale con le relative chiavi.

Tuttavia questo è solo uno scenario possibile. Nel mondo reale può essere necessario partire anziché da una descrizione concettuale, direttamente da dati, organizzati di norma in tabelle, dove però i dati possono essere ridondanti e dove diventa difficile la manutenzione.

Ipotizziamo che una società utilizzi un foglio Excel per memorizzare gli ordini per i propri prodotti, con una tabella come questa:

CodiceOrdineDataOrdineNomeClienteCognomeClienteEmailClienteViaIndirizzoCittaIndirizzoCAPCittaNomeProdottoPrezzoUnitarioQuantita
ORD-10012026-05-02MarioRossimrossi@es.itVia Torino 1Milano20121Tastiera50,001
ORD-10012026-05-02MarioRossimrossi@es.itVia Torino 1Milano20121Mouse30,002
ORD-10022026-05-03BiancaBrunobbruno@es.itPiazza Duomo 5Milano20123Tastiera50,001
ORD-10032026-05-10GiovanniNerigneri@es.itVia Garibaldi 2Torino10123Monitor200,001
ORD-10042026-05-12LauraVerdilverdi@es.itVia Torino 100Milano20154Mouse30,001
ORD-10042026-05-12LauraVerdilverdi@es.itVia Torino 100Milano20154Tastiera50,003

Vediamo le anomalie:

  • i dati di Mario Rossi e dell’indirizzo “Via Roma 1, Milano” sono ripetuti in due righe; stessa cosa per Laura Verdi. Se Mario cambia indirizzo, devo modificare tutte le sue righe.
  • NomeCliente, CognomeCliente, EmailCliente, ViaIndirizzo, CittaIndirizzo dipendono dall’identità del cliente, non dal codice ordine; PrezzoUnitario, NomeProdotto dipendono dal prodotto; CAPCitta dipende da CittaIndirizzo. Ogni modifica, inserimento, cancellazione vanno a impattare su tutti questi.

Occorre quindi scomporre la tabella nelle seguenti:

1. CLIENTE

IdCliente (PK)NomeCognomeEmail
C1MarioRossimrossi@es.it
C2BiancaBrunobbruno@es.it
C3GiovanniNerigneri@es.it
C4LauraVerdilverdi@es.it

2. INDIRIZZO

IdIndirizzo (PK)ViaCittaCAPIdCliente (FK)
I1Via Roma 1Milano20121C1
I2Corso Duomo 5Milano20123C2
I3Via Garibaldi 2Torino10123C3
I4Via Roma 100Milano20154C4

3. ORDINE

CodiceOrdine (PK)DataOrdineIdCliente (FK)
ORD-10012026-05-02C1
ORD-10022026-05-03C2
ORD-10032026-05-10C3
ORD-10042026-05-12C4

4. PRODOTTO (e tabella associativa per le righe d’ordine)

IdProdotto (PK)NomePrezzoUnitario
P1Tastiera50,00
P2Mouse30,00
P3Monitor200,00

5. RIGHE_ORDINE (tabella di relazione):

CodiceOrdine (FK)IdProdotto (FK)Quantita
ORD-1001P11
ORD-1001P22
ORD-1002P11
ORD-1003P31
ORD-1004P21
ORD-1004P13

Chiavi artificiali

Le chiavi primarie che abbiamo analizzato finora sono dette “naturali“, in quanto sono scelte dalle superchiavi di una entità. Esse possono essere singole (come le matricole per gli studenti o i codici fiscali) o multiple (come le coppie matricola-corso).

Tuttavia le chiavi naturali, specie se multiple, sebbene corrette da un punto di vista logico e concettuale, possono essere inefficienti e/o instabili.

Una chiave naturale è potenzialmente instabile perché proviene dal mondo reale (codice fiscale, partita IVA, email, ecc). I dati nel mondo reale cambiano, mentre l’identità del record no. Ad esempio se una azienda cambia dominio, deve rifare tutte le email dei dipendenti: se questi fossero identificati dall’email bisognerebbe non solo rifare tutte le chiavi primarie della tabella Utente, ma anche tutte le chiavi esterne delle tabelle ad essa collegate. Dal punto di vista logico l’utente è lo stesso, ma dal punto di vista tecnico distruggiamo dei record e li ricreiamo.

Una chiave naturale è anche potenzialmente inefficiente. Le chiavi primarie sono infatti sempre indicizzate (in un albero binario di ricerca) per una veloce ricerca, ma lo spazio occupato da una chiave ad esempio VARCHAR (di lunghezza variabile) richiede più tempo di calcolo rispetto ad una chiave di lunghezza fissa, specie se numerica. Può essere quindi costoso usare la chiave naturale se il database è di grandi dimensioni.

Per questa ragione sono state introdotte le chiavi artificiali. Esse sono chiavi generate automaticamente ed in modo univoco, alla creazione del record direttamente dal RDBMS. Ve ne sono principalmente di due tipi:

  • ID intero autoincrementale: valore chiave che parte da 1, e ad ogni inserimento di un nuovo record, si incrementa di 1 il valore. Il valore viene usato una volta soltanto, quindi se viene cancellato un record non viene riutilizzato un vecchio id. E’ il modello tipicamente usato sui database basati su SQL.
  • Stringa UUID (Universal Unique IDentifier), autogenerata non incrementale: non fornisce informazioni sul numero di record creati, inoltre garantisce che lo UUID sia univoco per ogni record di qualsiasi tabella: mentre con l’ID due tabelle distinte potrebbero record con lo stesso ID (anche se si riferiscono a istanze di entità differenti). E’ il modello usato sui database NoSQL per garantire iteroperabilità tra sistemi differenti (ad esempio in applicazioni distribuite). Può comunque essere usato anche nei database SQL.

Qui un esempio di tabella con ID autoincrementale:

IdMatricolaCodice fiscaleNomeCognomeEmail
1726265RSSMRA01A01F205ZMarioRossimrossi@cipiaceinfo.it
2726266BRNBNC02B42H501WBiancaBrunobbruno@cipiaceinfo.it
3726267GVNNNL00C15F205YGiovanniNerigneri@cipiaceinfo.it
4726268VRDLRA03D50L219XLauraVerdilverdi@cipiaceinfo.it

Le chiavi artificiali risolvono due tipologie di problemi delle chiavi naturali:

  • il dato artificiale identifica il dato-informazione, ma NON è parte dell’informazione stessa. La sua artificialità ne garantisce cioè la stabilità, quindi anche se cambia il valore della chiave naturale la sua identità rimane la stessa. Ipotizziamo ad esempio che l’università decida di cambiare l’intera valorizzazione delle matricole degli studenti per usare un codice a 7 cifre. Siccome quell’attributo è chiave primaria utilizzata da tutte le tabelle collegate come chiave esterna, bisogna in cascata modificare anche tutte le tabelle collegate, col rischio di forti inefficienze. Con una chiave artificiale questo non succede, perché l’Id non dipende da dati provenienti dal mondo reale.
  • Garantisce prestazioni ottimali: la chiave primaria è indicizzata in un albero di ricerca bilanciato che come noto fornisce le migliori prestazioni O(log n) nella ricerca della chiave. Le chiavi intere offrono sempre prestazioni migliori delle chiavi stringa, ed ancora di più sulle chiavi multiple.

Le chiavi artificiali però non eliminano il problema della normalizzazione. Esse danno un “falso senso di sicurezza” perché garantiscono come minimo una 2NF, almeno formalmente. Si tratta però di una “leggerezza” concettuale. Va sempre tenuto presente infatti che il modello logico-relazionale è qualcosa che è del tutto indipendente dalla sua implementazione fisica in un sistema reale. Metterli sullo stesso piano significa rischiare di confondere uno strumento tecnico (l’id artificiale) con un concetto logico (la dipendenza degli attributi da una chiave) col rischio di mantenere tutte le ridondanze e quindi le inconsistenze, con relative anomalie di inserimento, modifica e cancellazione.

Il modo corretto di operare è quindi quello di procedere alla creazione di chiavi primarie naturali, verificare la normalizzazione, e solo quando si è costruito un database normalizzato, aggiungere, solo nei casi in cui è prevista instabilità e/o inefficienza, un campo chiave artificiale aggiuntivo. Ma anche in questo caso, occorre nella fase di creazione tecnica, creare un vincolo di tipo UNIQUE, che garantisce che la chiave naturale (singola o composta) contenga comunque valori unici, indipendentemente dal valore dell’ID artificiale.

Infine, occorre ricordare di nuovo che l’ID artificiale è un dato tecnico dipendente dal sistema fisico, e quindi non dipendente dall’informazione trasportata. Questo significa che se per esempio si cancella il database e lo si ricrea, esso va a rigenerare un nuovo id per ogni istanza di ogni tabella, che può essere diverso da quello del database precedentemente utilizzato. Non è informazione significativa, ma solo dati tecnici per il funzionamento del database.

Nel caso degli ID autoincrementali va quindi trattato come tale: quando si espongono dati all’esterno (come nelle applicazioni distribuite) il dato dell’Id non va mai esposto ad altri sistemi. Discorso diverso lo merita lo UUID, che invece genera un ID globale, quindi condiviso tra più sistemi, e diventa parte dell’informazione. In quel caso il valore va preservato in caso di cancellazione e ripristino di un database.

Conclusioni

In questa lezione abbiamo visto i seguenti concetti fondamentali:

  • un database non è semplice agglomerato di tabelle, ma è una struttura matematica che prevede insiemi e vincoli dentro le tabelle (chiavi primarie) e tra tabelle (chiavi esterne);
  • le chiavi rappresentano attributi di una tabella da cui dipendono tutti gli altri attributi, in modo diretto
  • la normalizzazione è una tecnica di analisi che serve per garantire il raggiungimento delle 3 forme normali, più la forma normale di Boyce-Codd
  • è possibile usare chiavi artificiali per ragioni di stabilità ed efficienza, purché sia sempre chiaro che non sono parte dell’informazione, ma dati tecnici