Generazione di identificatori unici
Quando i computer hanno iniziato a connettersi attivamente in rete, è sorto un problema semplice ma molto urgente: come garantire che due dispositivi diversi, situati in parti diverse del mondo, non generino lo stesso identificatore?
Immagina: due server, uno a Tokyo e uno a Berlino, creano indipendentemente identificatori per oggetti. Se per caso generano lo stesso ID — i dati possono confondersi, sovrascriversi, e il sistema può andare in crash.
Così, negli anni '90, nell'epoca dello sviluppo esplosivo dei sistemi distribuiti e dei protocolli di rete, nei laboratori di Microsoft e Open Software Foundation (OSF) è nata l'idea del GUID — Globally Unique Identifier, cioè identificatore globale unico.
Il GUID (e nello standard ISO — UUID, Universally Unique Identifier) è un numero a 128 bit, che appare, ad esempio, così:
550e8400-e29b-41d4-a716-446655440000
È come un'impronta digitale digitale: è così lungo e caotico che la probabilità di collisione (due identificatori uguali) è praticamente nulla.
Viene creato usando:
- l'orario,
- numeri casuali,
- l'indirizzo MAC del dispositivo (nelle vecchie versioni),
- e persino funzioni hash crittografiche.
Perché era importante? Il punto è che il GUID ha permesso di creare identificatori unici senza server centrale, senza coordinazione, senza lock e senza ritardi. È stata una vera salvezza per:
- database distribuiti,
- protocolli di rete,
- sistemi di gestione documentale,
- e ovviamente le moderne API.
UUID in PostgreSQL
GUID/UUID si usano ovunque — da PostgreSQL ai servizi cloud. Sono diventati i costruttori invisibili di Internet moderno: senza di loro non potremmo collegare il mondo così facilmente.
In pratica è solo un numero casuale molto lungo di 16 byte, scritto in formato esadecimale. Semplicemente un intero molto lungo.
Questo tipo di dato è perfetto se vuoi garantire l'unicità dei valori a livello di tutto il sistema, senza dipendere da un generatore centralizzato di identificatori. È particolarmente utile nei sistemi distribuiti o quando i dati vengono generati su server diversi.
Perché non usare semplicemente INTEGER?
Verrebbe da chiedersi, perché serve UUID se si può usare un numero auto-incrementale come identificatore? Vediamo insieme:
Unicità globale: Se il tuo database gira su più server, garantire l'unicità di INTEGER è difficile. Con UUID il problema sparisce.
Sicurezza e offuscamento dati: UUID è più difficile da indovinare rispetto a un numero sequenziale. Questo riduce il rischio di leak di informazioni tramite identificatori prevedibili (tipo /users/1, /users/2).
Sistemi distribuiti: Se i dati vengono generati in parti diverse del sistema, un INTEGER auto-incrementale non va bene senza una sincronizzazione complicata.
Un altro vantaggio di UUID — è uno standard supportato in tanti linguaggi di programmazione e sistemi di storage.
Vantaggi dell'uso di UUID
I principali pro:
- Unicità: garantisce l'unicità dell'identificatore, anche se i dati vengono creati su server o sistemi diversi.
- Flessibilità: puoi usarlo per chiavi primarie, chiavi esterne e altri scopi.
- Scalabilità: comodissimo quando lavori con database distribuiti.
Però UUID ha anche i suoi svantaggi:
- Dimensione:
UUIDoccupa più spazio in memoria (16 byte) rispetto aINTEGER(4 byte). - Leggibilità: è relativamente più difficile da leggere e ricordare.
Generazione di UUID in PostgreSQL
Funzione integrata gen_random_uuid()
In PostgreSQL dalla versione 13 c'è la funzione integrata gen_random_uuid() per generare UUID casuali. Questa funzione restituisce un identificatore unico che puoi usare come valore per una colonna di tipo UUID.
Esempio:
SELECT gen_random_uuid();
Risultato:
d17fc23b-22e5-4fcb-bf86-1b4c766d77b7
Assicurati che l'estensione pgcrypto sia installata (per PSQL 1-12)
Nelle versioni precedenti di PostgreSQL (fino alla 12) la funzione gen_random_uuid() è disponibile dopo aver installato l'estensione pgcrypto. Se al lavoro ti obbligano a usarla, puoi salvare la situazione eseguendo il comando:
CREATE EXTENSION IF NOT EXISTS "pgcrypto";
Questo ti permetterà di usare la generazione di UUID casuali.
Uso di UUID come chiave esterna
UUID è comodissimo per creare relazioni tra tabelle. Supponiamo tu abbia una tabella utenti:
| id | name | |
|---|---|---|
| d17fc23b-22e5-4fcb-bf86-1b4c766d77b7 | Alice | alice@example.com |
| a1d3e15a-abc1-4b51-a320-2d4c859f7467 | Bob | bob@example.com |
| 3c524998-5c24-4e73-836d-a4c6bb3cafcd | Charlie | charlie@example.com |
Creazione della tabella orders
Creiamo la tabella orders, dove user_id sarà una chiave esterna che punta a id nella tabella users.
| order_id | user_id | order_date |
|---|---|---|
| 1a5b7d9c-b1a2-4f8e-9e7a-0a1111111111 | d17fc23b-22e5-4fcb-bf86-1b4c766d77b7 | 2024-10-15 10:00:00 |
| 2b6c8e0d-c2b3-5a9f-af8b-1b2222222222 | a1d3e15a-abc1-4b51-a320-2d4c859f7467 | 2024-10-15 10:05:00 |
| 3c7d9f1e-d3c4-6baf-bc9c-2c3333333333 | 3c524998-5c24-4e73-836d-a4c6bb3cafcd | 2024-10-15 10:10:00 |
| 4d8eaf2f-e4d5-7cb0-cdab-3d4444444444 | d17fc23b-22e5-4fcb-bf86-1b4c766d77b7 | 2024-10-15 10:15:00 |
| 5e9fb030-f5e6-8dc1-debc-4e5555555555 | a1d3e15a-abc1-4b51-a320-2d4c859f7467 | 2024-10-15 10:20:00 |
Il campo user_id è collegato al campo id della tabella users, così puoi creare relazioni tra utenti e i loro ordini.
Query con JOIN
Vediamo come sono collegati i dati nelle tabelle users e orders:
SELECT
u.id AS user_id,
u.name,
o.order_id,
o.order_date
FROM users u
JOIN orders o ON u.id = o.user_id;
Risultato:
| user_id | name | order_id | order_date |
|---|---|---|---|
| d17fc23b-22e5-4fcb-bf86-1b4c766d77b7 | Alice | a1d3e15a-abc1-4b51-a320-2d4c859f7467 | 2024-10-20 12:34:56 |
Principali scenari d'uso di UUID
Identificatori di utenti e ordini: nei sistemi distribuiti, dove i dati possono arrivare da fonti diverse.
Etichette per API: UUID viene spesso usato nelle REST API per identificare le entità.
Sincronizzazione globale dei dati: ad esempio, quando i dati vengono raccolti da server diversi.
Errori tipici e particolarità
Tentativo di generare UUID a mano: meglio usare le funzioni integrate, tipo gen_random_uuid(), per evitare errori.
Uso eccessivo: non usare UUID dove basta un INTEGER auto-incrementale. Per esempio, in tabelle locali che non saranno mai scalate.
Dimensione: UUID occupa più spazio, il che può influire sulle performance delle query, soprattutto sugli indici.
GO TO FULL VERSION