web-dev-qa-db-fra.com

Stocker l'UUID v4 dans MySQL

Je génère des UUID en PHP, selon la fonction trouvée ici

Maintenant, je veux stocker cela dans une base de données MySQL. Quel est le format de champ MySQL le meilleur/le plus efficace pour stocker UUID v4?

J'ai actuellement varchar (256), mais je suis presque sûr que c'est beaucoup plus gros que nécessaire. J'ai trouvé beaucoup de réponses presque, mais ils sont généralement ambigus sur la forme de l'UUID à laquelle ils font référence, alors je demande le format spécifique.

9
Stephen R

Stockez-le en tant que VARCHAR(36) si vous souhaitez un ajustement exact, ou VARCHAR(255) qui fonctionnera avec le même coût de stockage de toute façon. Il n’ya aucune raison de s’embarrasser d'octets ici.

Rappelez-vous que les champs VARCHAR sont longueur variable , le coût de stockage est donc proportionnel à la quantité de données réellement stockée, pas à la quantité de données qui pourrait en être contenue.

Le stocker sous la forme BINARY est extrêmement gênant, les valeurs ne sont pas imprimables et peuvent apparaître comme des ordures lors de l'exécution de requêtes. Il y a rarement une raison d'utiliser la représentation binaire littérale. Les valeurs lisibles par l'homme peuvent être copiées-collées et manipulées facilement.

Certaines autres plates-formes, telles que Postgres, ont une colonne UUID appropriée qui le stocke en interne dans un format plus compact, mais l'affiche sous forme lisible par l'homme, vous permettant ainsi de tirer le meilleur parti des deux approches.

22
tadman

La question concerne le stockage d'un UUID dans MySQL.

Depuis la version 8.0 de MySQL, vous pouvez utiliser binary(16) avec la conversion automatique via les fonctions UUID_TO_BIN/BIN_TO_UUID: https://mysqlserverteam.com/mysql-8-0-uuid-support/

Sachez que mySQL dispose également d’un moyen rapide de générer des UUID en tant que clé primaire:

INSERT INTO t VALUES (UUID_TO_BIN (UUID (), true))

6
Karsten R.

Si vous avez toujours un UUID pour chaque ligne, vous pouvez le stocker sous la forme CHAR(36) et économiser 1 octet par ligne sur VARCHAR(36).

uuid CHAR(36) CHARACTER SET ascii

Contrairement à CHAR, les valeurs VARCHAR sont stockées sous forme de 1 octet ou de 2 octets préfixe de longueur plus données. Le préfixe de longueur indique le nombre de octets dans la valeur. Une colonne utilise un octet de longueur si les valeurs nécessitent n ° plus de 255 octets, deux octets de longueur si les valeurs peuvent nécessiter plus de 255 octets . https://dev.mysql.com/doc/refman/5.7/en/char.html

Bien que soyez prudent avec CHAR, il utilisera toujours toute la longueur définie même si le champ est laissé vide. Assurez-vous également que vous utilisez ASCII pour le jeu de caractères, car CHAR planifierait sinon le pire scénario possible (c.-à-d. 3 octets par caractère dans utf8, 4 dans utf8mb4).

[...] MySQL doit réserver quatre octets pour chaque caractère d'un CHAR CHARACTER SET colonne utf8mb4 car il s'agit du maximum possible longueur. Par exemple, MySQL doit réserver 40 octets pour un CHAR (10) CARACTERE SET colonne utf8mb4 . https://dev.mysql.com/doc/refman/5.5/en/charset-unicode-utf8mb4.html

6
Mathieu Rey

Le plus efficace est certainement BINARY(16), le stockage des caractères lisibles par l'homme utilisant plus du double de l'espace de stockage, ce qui signifie des index plus grands et une recherche plus lente. Si vos données sont suffisamment petites pour être stockées sous forme de texte ne nuit pas aux performances, vous n'avez probablement pas besoin d'UUID sur des clés entières ennuyeuses. Stocker les fichiers bruts n’est vraiment pas aussi pénible que certains le suggèrent, car tout outil d’administration de base de données digne de ce nom affichera/affichera les octets sous forme hexadécimale, plutôt que comme octets littéraux de "texte". Vous ne devriez pas avoir besoin de rechercher manuellement les UUID dans la base de données; si vous devez le faire, les littéraux HEX() et x'deadbeef01' sont vos amis. Il est trivial d’écrire une fonction dans votre application - comme celle que vous avez référencée - pour gérer cela pour vous. Vous pourriez probablement même le faire dans la base de données sous forme de colonnes virtuelles et de procédures stockées afin que l'application ne se préoccupe jamais des données brutes.

Je séparerais la logique de génération d'UUID de la logique d'affichage pour m'assurer que les données existantes ne sont jamais modifiées et que les erreurs sont détectables:

function guidv4($prettify = false)
{
    static $native = function_exists('random_bytes');
    $data = $native ? random_bytes(16) : openssl_random_pseudo_bytes(16);

    $data[6] = chr(ord($data[6]) & 0x0f | 0x40); // set version to 0100
    $data[8] = chr(ord($data[8]) & 0x3f | 0x80); // set bits 6-7 to 10

    if ($prettify) {
        return guidv4_pretty($data);
    }
    return $data;
}

function guidv4_pretty($data)
{
    return strlen($data) == 16 ?
        vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4)) :
        false;
}

function guidv4_ugly($data)
{
    $data = preg_replace('/[^\\dA-F]+/i', '', $data);
    return strlen($data) == 32 ? hex2bin($data) : false;
}

Edit: Si vous avez seulement besoin de la jolie colonne lors de la lecture de la base de données, une instruction comme celle-ci suffit:

ALTER TABLE test ADD uuid_pretty CHAR(36) GENERATED ALWAYS AS (CONCAT_WS('-', LEFT(HEX(uuid_ugly), 8), SUBSTR(HEX(uuid_ugly), 9, 4), SUBSTR(HEX(uuid_ugly), 13, 4), SUBSTR(HEX(uuid_ugly), 17, 4), RIGHT(HEX(uuid_ugly), 12))) VIRTUAL;
1
Walf