Générer des UUIDv4 depuis MySQL

Introduction

Les UUID sont de plus en plus utiliser pour identifier des resources dans une base de données. Ils sont généralement générer avec l'insertion de vos données. Néanmoins, ils y a des cas où générer l'UUID depuis MySQL peut être très utile. Je pense notamment à la migration de données ou à l'import de données ne possédant pas d'UUID. Pour des raisons de performance, ces scripts sont généralement écrit entièrement en SQL, il n'est donc pas possible d'utiliser une quelqu'un lib d'un autre langage pour générer nos UUID.

UUIDv1 vs UUIDv4

MySQL propose une function native UUID() qui malheureusement ne génère que des UUIDv1. Les UUIDv1 comporte une partie déterminé à partir de l'adresse physique de la machine et de la date, puis une partie aléatoire. Ainsi, vos UUIDv1 sont garantie d'être unique à moins d'être générer du même ordinateur exactement au même moment.

Voici plusieurs UUIDv1 généré de la même machine avec MysQL :

42055f6a-64d1-11e8-b715-0800270e8075
747bb804-64d2-11e8-b715-0800270e8075
78143c50-64d2-11e8-b715-0800270e8075
7b3cd91d-64d2-11e8-b715-0800270e8075

On peut voir que seul la première partie des UUID change.

Les UUIDv4 sont généré d'une manière plus simple. Chaque partie est généré aléatoirement sans logique particulière. Il est donc théoriquement possible de générer deux fois le même UUIDv4, mais avec 2^128 combinaisons possibles, les chances de collision sont si faibles qu'on le considère unique.

0ecb327f-d019-441d-a909-7903ecc634d7
d29c6b29-9ff8-4473-811d-de5e77f1bc9c
ce46d1df-ae8b-4377-8cb2-f31bb3eaaa3f
b3e021bb-8d05-4c03-bfc7-5be9247fa2bf

Fonction MySQL

Voici donc une fonction MySQL pour générer un UUIDv4 :

-- Change delimiter so that the function body doesn't end the function declaration
DELIMITER //

CREATE FUNCTION uuid_v4()
    RETURNS CHAR(36)
BEGIN
    -- Generate 8 2-byte strings that we will combine into a UUIDv4
    SET @h1 = LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0');
    SET @h2 = LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0');
    SET @h3 = LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0');
    SET @h6 = LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0');
    SET @h7 = LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0');
    SET @h8 = LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0');

    -- 4th section will start with a 4 indicating the version
    SET @h4 = CONCAT('4', LPAD(HEX(FLOOR(RAND() * 0x0fff)), 3, '0'));

    -- 5th section first half-byte can only be 8, 9 A or B
    SET @h5 = CONCAT(HEX(FLOOR(RAND() * 4 + 8)),
                LPAD(HEX(FLOOR(RAND() * 0x0fff)), 3, '0'));

    -- Build the complete UUID
    RETURN LOWER(CONCAT(
        @h1, @h2, '-', @h3, '-', @h4, '-', @h5, '-', @h6, @h7, @h8
    ));
END
//
-- Switch back the delimiter
DELIMITER ;

Une fois créée dans votre base de données, vous pourrez utiliser la fonction de la façon suivante :

SELECT uuid_v4();

directement dans un INSERT :

INSERT INTO foobar (`uuid`) VALUES (uuid_v4());

ou dans un UPDATE :

UPDATE foobar SET uuid = uuid_v4();

Les commentaires