▦ Dati e database

Chiavi primarie naturali o surrogate: come scegliere

Codice fiscale, email o un numero progressivo? Pro e contro delle chiavi naturali e surrogate, con criteri pratici per scegliere la chiave di una tabella.

Ogni tabella di un database relazionale dovrebbe avere una chiave primaria: una colonna, o un insieme di colonne, che identifica ogni riga in modo univoco e non può essere vuota. La domanda che si pone quasi sempre in fase di progettazione è se usare un dato che esiste già nel mondo reale, come un codice fiscale o un indirizzo email, oppure un identificativo creato apposta dal database. La scelta ha conseguenze che si scoprono spesso anni dopo.

Due famiglie di chiavi

Una chiave naturale è un attributo che ha già un significato al di fuori del database: il codice fiscale di una persona, la partita IVA di un'azienda, il codice ISBN di un libro, la targa di un veicolo, il codice IBAN di un conto.

Una chiave surrogata è un valore senza significato, generato dal sistema solo per identificare la riga: un intero progressivo (1, 2, 3…) o un identificativo universale (UUID).

I vantaggi delle chiavi naturali

Le chiavi naturali hanno un'attrattiva evidente:

  • non serve una colonna in più, perché il dato si deve memorizzare comunque;
  • impediscono di per sé i duplicati: due righe con lo stesso codice fiscale vengono rifiutate;
  • rendono leggibili le tabelle collegate, perché nella tabella degli ordini si vede subito a chi si riferiscono.

I problemi delle chiavi naturali

Il difficile è che i dati del mondo reale cambiano più spesso di quanto si pensi, e una chiave primaria dovrebbe restare stabile per sempre.

Il valore può cambiare

Un indirizzo email si cambia di continuo. Anche un codice fiscale, che sembra immutabile, può essere rettificato se era stato calcolato con dati sbagliati. Quando una chiave cambia, il cambiamento va propagato a tutte le tabelle che la usano come riferimento: operazione possibile, ma rischiosa e lenta su grandi quantità di dati.

Il valore può mancare

Un cliente straniero può non avere un codice fiscale italiano. Un'azienda in fase di costituzione può non avere ancora una partita IVA. Se la chiave è obbligatoria, non si potrà registrare quel soggetto, oppure si inventeranno valori fittizi che sporcano i dati.

Il valore può non essere davvero unico

Molti identificativi «unici» lo sono solo in teoria. Esistono casi di omocodia nei codici fiscali, risolti con un meccanismo apposito, e non tutti i sistemi lo gestiscono correttamente. Gli identificativi assegnati da terzi possono anche essere riassegnati nel tempo.

Il valore può essere un dato personale

Usare il codice fiscale come chiave significa propagarlo in ogni tabella collegata, nei log, negli URL e nei file di esportazione. Ogni copia è un dato personale in più da proteggere.

I vantaggi delle chiavi surrogate

Una chiave surrogata non ha nessuno di questi problemi: non cambia mai, esiste sempre fin dalla creazione della riga, è unica per costruzione e non rivela nulla. Inoltre è compatta: un intero occupa pochi byte, e gli indici e le relazioni costruiti su di esso sono veloci.

CREATE TABLE clienti (
  id_cliente     BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  codice_fiscale CHAR(16) UNIQUE,
  email          TEXT NOT NULL UNIQUE,
  nome           TEXT NOT NULL
);

In questo esempio la chiave primaria è surrogata, ma il codice fiscale e l'email restano protetti da un vincolo UNIQUE. È il punto più importante: una chiave surrogata non elimina la necessità di vincoli di unicità sui dati reali. Senza il vincolo, nulla impedisce di inserire lo stesso cliente due volte con due id diversi.

Interi progressivi o UUID

Tra le chiavi surrogate ci sono due scelte principali.

Aspetto Intero progressivo UUID
Dimensione 4 o 8 byte 16 byte
Leggibilità Semplice da dettare e confrontare Lungo e scomodo da leggere
Generazione Dal database, in sequenza Ovunque, anche offline o lato applicazione
Prevedibilità Si indovina l'id successivo Non prevedibile
Unione di database diversi Collisioni probabili Collisioni praticamente impossibili

Un intero progressivo è la scelta più semplice per la maggior parte delle applicazioni. Gli UUID sono utili quando più sistemi creano record in modo indipendente, quando si devono unire dati provenienti da fonti diverse o quando l'id compare in un indirizzo web e non si vuole che qualcuno possa scorrere i record cambiando un numero. Va però ricordato che nascondere l'id non sostituisce un controllo dei permessi: ogni richiesta deve comunque verificare che l'utente possa vedere quel record.

Gli UUID completamente casuali, inseriti in un indice ordinato, causano scritture sparse in punti diversi dell'indice. Le versioni ordinate nel tempo, come gli UUID versione 7, attenuano questo problema.

Quando la chiave naturale va bene

Esistono casi in cui una chiave naturale è la scelta più sensata:

  • tabelle di codifica stabili, come i codici ISO dei paesi o delle valute, che cambiano raramente e sono standard;
  • tabelle ponte delle relazioni molti a molti, dove la chiave composta dalle due chiavi esterne è naturale e sufficiente;
  • dati interni il cui codice è deciso e controllato dalla stessa organizzazione e non verrà mai riassegnato.

In sintesi

  • La chiave primaria deve essere unica, sempre presente e stabile nel tempo.
  • Le chiavi naturali sono comode ma possono cambiare, mancare o contenere dati personali.
  • Le chiavi surrogate sono stabili e compatte, ma vanno affiancate da vincoli UNIQUE sui dati reali.
  • Interi progressivi per la maggior parte dei casi, UUID per sistemi distribuiti o id esposti.
  • Le chiavi naturali restano adatte a codifiche standard e tabelle ponte.
MM
Marco Marzaduri

Marco Marzaduri si occupa di cybersecurity, informatica forense e sviluppo web. Laureato in informatica e in psicologia, unisce l'analisi tecnica alla comprensione del fattore umano.

Leggi anche