Utilizzo e conseguenze di UUID/GUID come indici dei record

Preambolo

Articolo liberamente ispirato all’originale di Richard Clayton, del quale condivido molti aspetti pratici e tecnici.

Premessa

Ultimamente ho avuto modo di lavorare e pensare molto all’UUID. Il sistema che stiamo sviluppando è afflitto dal suo utilizzo. Per molti sviluppatori, l’UUID sembra un modo assolutamente fantastico per stabilire l’identità di un record in un sistema. Davvero bello poter generare un ID unico per ogni sistema nel mondo, non è così?

Lo scopo di questo post invece è discutere proprio sugli usi appropriati e inappropriati degli UUID. Il mio obiettivo è incoraggiare lo sviluppatore a pensare alle conseguenze generali della selezione del tipo di dati per gli identificatori nelle loro architetture.

Un pò di tecnicismi

Per la maggior parte dei database, gli UUID sono solo 36 stringhe di caratteri.
Database come MySQL non hanno un’implementazione nativa della struttura dati. Ciò significa che la colonna che trasporta il valore deve essere almeno di 36 caratteri (VARCHAR(36)). Quando si considera la codifica del testo (ad esempio il set di caratteri MySQL) utilizzato per rappresentare le stringhe, ciò potrebbe significare 2-3 byte per carattere (se si utilizza UTF-8). Ciò significa almeno 72 byte per identificatore!

Anche se questo non sembra un grosso problema, considera che per ogni 13.889 identificatori, il tuo database consumerà 1 MB di spazio di archiviazione. Se si utilizzano chiavi esterne e sono anche UUID, questo è un altro 1 MB di spazio di archiviazione per ogni chiave esterna…

SVANTAGGI

  • Gli UUID degradano le prestazioni del database.

    Se si utilizza un UUID come identificatore per una tabella, è necessario indicizzarlo. Ma sfortunatamente, gli UUID non indicizzano bene, per via della loro dimensione e casualità. Gli indici sono strutture che crescono e si diramano quando aggiungi altri dati. I valori sequenziali tendono a indicizzare bene perché non richiedono il riallineamento di ampie sezioni dell’indice. Gli UUID sono progettati per essere non sequenziali e sono molto grandi rispetto a un intero. Ciò significa che più UUID si inseriranno, maggiore sarà la penalità di inserimento.
    Si guardi ad esempio queste statistiche: http://kccoder.com/mysql/uuid-vs-int-insert-performance/ . Il tempo di inserimento di un intero lungo rispetto all’UUID è quasi costante. Davvero delle statistiche interessanti!
    Si badi inoltre alle prestazioni migliori anche nelle query che usano gli interi, sebbene questo non sia così pronunciato.
    Gli interi incrementati automaticamente saranno quasi sempre più piccoli, il che significa che le scansioni su tabelle e record saranno più efficienti. D’altra parte, l’indice che memorizza gli identificatori UUID crescerà in maniera maggiore e ad un ritmo più veloce degli interi. Ciò significa che un indice UUID inciderà sulle prestazioni perchè ricercabile sempre solo sul disco (poiché non può adattarsi completamente alla memoria) in modo più veloce di un indice intero.

  • L’UUID è la struttura dati corretta per l’attività?

    L’uso di un UUID è l’avere un identificatore univoco universale. Di solito ci sono due ragioni per usarlo: Non si desidera un database per controllare a livello centrale l’identità dei record oppure c’è la possibilità che più componenti possano generare autonomamente un identificatore non univoco.
    Ma queste preoccupazioni dovrebbero in genere venir prese in considerazione solo quando ci si trova in un ambiente concorrente o distribuito. La domanda corretta allora è: il tuo software ha effettivamente necessità e strutture di concorrenza e distribuzione per l’HA?

Sicuramente è possibile evitare l’uso degli UUID in favore degli indici numerici in tutta una serie di casistiche. In caso in cui la nostra applicazione scriva i record su un singolo database (o un cluster in configurazione master / slave). Oppure ancora se parti della struttura dati aggiorneranno più di una tabella (e sarà necessario l’ID prima di inserire record in quelle altre tabelle in una singola transazione).

È possibile ancora evitare l’uso degli UUID utilizzando chiave naturali per i record.
Una chiave naturale è una proprietà o un gruppo di proprietà che rendono il tuo record unico. Un numero di telefono o un numero di previdenza sociale potrebbe fungere da identificatore univoco. In un sistema distribuito, questa potrebbe essere la combinazione di IP server, applicazione e data/ora. Il punto è che potrebbe non esserci la necessità di avere un UUID per stabilire l’identità del record in un database.
Se è necessario distribuire le scritture tra i server, è possibile semplicemente eseguire l’hash della chiave naturale (concatenando i campi se si tratta di un composito) per un identificativo univoco. Se la strategia di hashing è ben nota tra i componenti dell’architettura, non sarà necessario memorizzare l’hash (poiché i componenti sapranno come rigenerarlo al volo quando si eseguono le ricerche).

Infine, e questo è il caso che generalmente spinge all’utilizzo degli uuid è Quando sia necessario presentare un ID a un utente utilizzatore del software.
Consideriamo ad esempio la creazione di un’applicazione HR per una piccola azienda (30 dipendenti). Un UUID ha senso per un ID dipendente? Chi potrebbe immaginare di avere il proprio numero di impiegato simile ad un codice uuid (2a6db8e1-8967-4511-9839-a7cb3a895710)? Ovviamente nessuno! Chiunque sarebbe abituato ad un numero più amichevole e più facile da ricordare.

C’è un ulteriore esempio chiarificatore dell’uso degli uuid visibili agli utenti utilizzatori, utilizzabili all’interno delle URI di cui utenti e sviluppatori di applicazioni dovrebbero sempre tener conto:

Dati due URI
http://www.esempio.it/utente/2a6db8e1-8967-4511-9839-a7cb3a895710/task/65c25b81-e1e8 -4cbd-a112-e00d0bddef65
O
http://www.esempio.it/utente/345123/task/12

È sicuramente più facile ricordare il secondo URL piuttosto che il secondo. Questo è chiaro. Quale il motivo di utilizzare il primo approccio, se non quello di camuffare dati sensibili agli utenti? Ma per farlo, bisognerebbe pensare piuttosto ad approcci lato software piuttosto che lato database che potrebbero ricondurci ad esempio a chiavi di tipo naturali, o ancora riscrittura degli URI.

Conclusione

L’UUID dovrebbe essere una tattica di ultima istanza, impiegata solo dopo aver esaurito altre strategie per determinare l’unicità in un’architettura. In un database, sono generalmente considerati un anti-pattern e dovrebbero essere evitati a causa dei limiti prestazionali nell’indicizzazione dei loro valori. Inoltre l’UUID non è particolarmente amichevole per gli utenti, nè tantomeno per i dev. Dunque, si dovrebbe provare ad usare chiavi naturali il più possibile e gli interi auto incrementati come alternativa (quando ha senso).

 

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *

Su questo sito utilizziamo cookie tecnici e, previo tuo consenso, cookie di profilazione, nostri e di terze parti, per proporti pubblicità in linea con le tue preferenze.
Cliccando il pulsante accetto presti il consenso al loro uso.