UUID

Que sont les UUID ?

L’acronyme UUID signifie Universally Unique Identifier, qui se traduit par identifiant universel unique.

Nuances avec les identifiants « classiques »

Habituellement, on utilise un ID incrémenté dont le champ dispose d’un index unique, ou bien est typé clé primaire ce qui revient au même. Dans ce cas, chaque identifiant est unique au sein d’une table, mais pas globalement dans la base de données. Chaque valeur peut exister dans toutes les tables. Les ID classiques sont des valeurs généralement numériques dont la taille varie puisque stockée sur autant d’octets que nécessaire selon la valeur. La valeur pouvant aller de 1 à plusieurs millions / milliards selon les systèmes.

A contrario, un UUID est unique pour l’intégralité de la BDD est ne nécessite pas d’index unique (ce qui pour le coup, risquerait de dégrader les performances). Cette unicité est garantie par l’algorithme de calcul qui permet une quantité immensément importantes de combinaisons. Un UUID nécessite 16 octets pour être stocké.

Remarque : on trouve souvent le terme GUID. Il s’agit d’une implémentation propre à Microsoft des UUID version 4.

Le format permet vraiment qu’un UUID soit unique ?

Un UUID est codé sur 128 bits et prend la forme d’une chaine de 36 caractères, dont 4 tirets utilisés comme séparateurs. Cela fait donc 32 caractères, découpés en 5 chaines de chiffres hexadécimaux.

Bien que cela permette une quantité astronomiques de valeurs et contrairement à ce que laisse penser ce nom, les algorithmes permettant de générer des UUID ne garantissent pas à 100% d’obtenir un identifiant unique. Mais la probabilité d’obtenir un doublon est extrêmement faible.

Versions d’UUID

Versions 1, 2 et 6

La version 1 est basée sur l’adresse MAC et l’horodatage jusqu’aux secondes, ce qui lui permettrait de générer plusieurs millions d’UUID uniques chaque seconde ! L’inconvénient majeur est que l’adresse MAC de la machine est révélée.

La version 2 est quasi similaire à la première. Elle inclue simplement quelques informations supplémentaires.

La version 6 est similaire à ceci prêt que les données basée sur l’horodate sont inversées. Par rapport à la v1, cela permet simplement de faire un tri sur l’ordre de création des UUID.

Versions 3 et 5

La version 3 consiste à générer un hash MD5 d’un nom (quel qu’il soit, exemples : une catégorie, un répertoire, une URL…).

La version 5 est similaire à la version 3 mais utilise l’algorithme SHA-1 en remplacement du MD5.

Version 4 et 8

La version 4 génère associe des combinaisons de nombres étant chacune totalement aléatoire, sans être basée sur le temps. Chaque valeur est donc totalement imprévisible.

La version a un fonctionnement similaire, si ce n’est qu’ici les différentes suites de caractères entre chaque séparateur peuvent être personnalisées. La valeur 8 doit toutefois obligatoirement figurer à la bonne position, afin de permettre (comme pour les autres versions) qu’il s’agit d’un UUID v8.

Version 7

Tout comme la version 1, le version 7 est basée sur le temps, tout comme la version 1. Elle permet encore plus d’unicité à la seconde, ce qui s’avère particulièrement intéressant pour les applications à charge conséquente.

Identifier la version d’un UUID

Un UUID prend donc cette forme : e1bb852c-cbdd-4181-afct-18e5c621cf19.

Selon les versions, tous les caractères sont aléatoires, mais qu’importe la version, il y en a toujours 2 qui sont fixes. Dans cet exemple, les 2 caractères en gras, le chiffre 4 et la lettre a. Cela indique qu’il s’agit d’un UUID version 4, variante a.

Comment générer un UUID ?

Certains langages le permettent nativement, mais la plupart il est nécessaire d’intégrer une bibliothèque dédiée et de lui indiquer la version de l’UUID à générer. Il n’est pas nécessaire de connaitre les algorithmes de chaque version, ce qui rend l’utilisation des UUID très simple et accessible.

Implémentation dans MySQL

La gestion des UUID dans MySQL présente de gros soucis de performances. Si bien qu’il n’est pas rare d’avoir des applications combinant ID et UUID. Les ID étant utilisés par l’application elle-même et les UUID pour les échanges avec l’extérieur comme cela pourrait être le cas avec une API par exemple.

MySQL ne sachant pas gérer les UUID, nous sommes contraints des les stocker dans un champ textuel. D’où les problèmes de performances, mais aussi de stockage car le texte pèse plus qu’un entier.

La version 8 de MySQL propose des nouveautés pour améliorer les performances :

  • IS_UUID
  • UUID : Génère un UUID.
  • UUID_TO_BIN : Converti un UUID textuel sous sa forme binaire (moins lourde et mieux gérée par la BDD). On le stockera alors dans un champ de type BINARY(16).
  • BIN_TO_UUID : Opération inverse de UUID_TO_BIN.

L’inconvénient est les opérations et la rédaction sont alourdies :

CREATE TABLE customers (
    id BINARY(16) PRIMARY KEY,
    name VARCHAR(255)
);

// Il faut utiliser 2 méthodes en insertion / mise à jour / suppression
INSERT INTO customers (id, name) VALUES
  (UUID_TO_BIN(UUID()), 'John Doe'),
  (UUID_TO_BIN(UUID()), 'Will Smith'),
  (UUID_TO_BIN(UUID()), 'Mary Jane');

// Il faut convertir les UUID à chaque opération, même la lecture
SELECT 
  BIN_TO_UUID(id) id, 
  name
FROM customers;