Question

Est-ce que j'utilise varchar (36) ou existe-t-il de meilleurs moyens de le faire?

Était-ce utile?

La solution

Mon administrateur de base de données m'a demandé, quand je lui ai demandé quelle était la meilleure façon de stocker les GUID de mes objets, pourquoi je devais stocker 16 octets alors que je pouvais faire la même chose en 4 octets avec un entier. Depuis qu'il m'a lancé ce défi, je pensais que le moment était venu de le mentionner. Cela étant dit ...

Vous pouvez stocker un GUID sous la forme d'un binaire CHAR (16) si vous souhaitez utiliser au mieux l'espace de stockage.

Autres conseils

Je l'enregistrerais sous la forme d'un caractère (36).

En ajoutant à la réponse de ThaBadDawg, utilisez ces fonctions pratiques (grâce à un de mes collègues plus sages) pour passer de la longueur de 36 chaînes à un tableau de 16 octets.

DELIMITER $

CREATE FUNCTION `GuidToBinary`(
    $Data VARCHAR(36)
) RETURNS binary(16)
DETERMINISTIC
NO SQL
BEGIN
    DECLARE $Result BINARY(16) DEFAULT NULL;
    IF $Data IS NOT NULL THEN
        SET $Data = REPLACE($Data,'-','');
        SET $Result =
            CONCAT( UNHEX(SUBSTRING($Data,7,2)), UNHEX(SUBSTRING($Data,5,2)),
                    UNHEX(SUBSTRING($Data,3,2)), UNHEX(SUBSTRING($Data,1,2)),
                    UNHEX(SUBSTRING($Data,11,2)),UNHEX(SUBSTRING($Data,9,2)),
                    UNHEX(SUBSTRING($Data,15,2)),UNHEX(SUBSTRING($Data,13,2)),
                    UNHEX(SUBSTRING($Data,17,16)));
    END IF;
    RETURN $Result;
END

$

CREATE FUNCTION `ToGuid`(
    $Data BINARY(16)
) RETURNS char(36) CHARSET utf8
DETERMINISTIC
NO SQL
BEGIN
    DECLARE $Result CHAR(36) DEFAULT NULL;
    IF $Data IS NOT NULL THEN
        SET $Result =
            CONCAT(
                HEX(SUBSTRING($Data,4,1)), HEX(SUBSTRING($Data,3,1)),
                HEX(SUBSTRING($Data,2,1)), HEX(SUBSTRING($Data,1,1)), '-', 
                HEX(SUBSTRING($Data,6,1)), HEX(SUBSTRING($Data,5,1)), '-',
                HEX(SUBSTRING($Data,8,1)), HEX(SUBSTRING($Data,7,1)), '-',
                HEX(SUBSTRING($Data,9,2)), '-', HEX(SUBSTRING($Data,11,6)));
    END IF;
    RETURN $Result;
END
$

CHAR (16) est en fait un BINARY (16) , choisissez votre saveur préférée

Pour mieux suivre le code, prenons l'exemple donné ci-dessous du GUID ordonné par chiffre. (Les caractères illicites sont utilisés à des fins d'illustration - chacun place un caractère unique.) Les fonctions transformeront l'ordre des octets pour obtenir un ordre de bits pour une mise en cluster d'index supérieure. Le guide réorganisé est présenté sous l'exemple.

12345678-9ABC-DEFG-HIJK-LMNOPQRSTUVW
78563412-BC9A-FGDE-HIJK-LMNOPQRSTUVW

Tirets supprimés:

123456789ABCDEFGHIJKLMNOPQRSTUVW
78563412BC9AFGDEHIJKLMNOPQRSTUVW

car (36) serait un bon choix. Vous pouvez également utiliser la fonction UUID () de MySQL, qui renvoie un format de texte de 36 caractères (hex avec traits d'union) pouvant être utilisé pour récupérer ces identifiants à partir de la base de données.

" Mieux " dépend de ce que vous optimisez.

À quel point la taille / les performances du stockage vous importent-elles par rapport à la facilité de développement? Plus important encore: générez-vous suffisamment d’importants GUID ou les récupérez-vous assez souvent?

Si la réponse est "non", car (36) est plus que suffisant, et il est extrêmement simple de stocker / récupérer des GUID. Sinon, binary (16) est raisonnable, mais vous devrez vous appuyer sur MySQL et / ou le langage de programmation de votre choix pour effectuer la conversion à partir de la représentation de chaîne habituelle.

Binaire (16) conviendrait mieux que l’utilisation de varchar (32).

La routine GuidToBinary publiée par KCD doit être modifiée pour tenir compte de la structure de bits de l'horodatage dans la chaîne GUID. Si la chaîne représente un UUID de version 1, semblable à ceux renvoyés par la routine uuid () mysql, les composants time sont incorporés dans les lettres 1-G, à l’exclusion de D.

12345678-9ABC-DEFG-HIJK-LMNOPQRSTUVW
12345678 = least significant 4 bytes of the timestamp in big endian order
9ABC     = middle 2 timestamp bytes in big endian
D        = 1 to signify a version 1 UUID
EFG      = most significant 12 bits of the timestamp in big endian

Lorsque vous convertissez en binaire, le meilleur ordre pour l'indexation serait: EFG9ABC12345678D + le reste.

Vous ne voulez pas échanger 12345678 en 78563412 car big endian donne déjà le meilleur ordre d'octets d'indice binaire. Cependant, vous voulez que les octets les plus significatifs soient déplacés devant les octets inférieurs. Par conséquent, EFG commence en premier, suivi des bits du milieu et des bits inférieurs. Générez une douzaine d'UUID avec uuid () en l'espace d'une minute et vous devriez voir comment cet ordre génère le bon classement.

select uuid(), 0
union 
select uuid(), sleep(.001)
union 
select uuid(), sleep(.010)
union 
select uuid(), sleep(.100)
union 
select uuid(), sleep(1)
union 
select uuid(), sleep(10)
union
select uuid(), 0;

/* output */
6eec5eb6-9755-11e4-b981-feb7b39d48d6
6eec5f10-9755-11e4-b981-feb7b39d48d6
6eec8ddc-9755-11e4-b981-feb7b39d48d6
6eee30d0-9755-11e4-b981-feb7b39d48d6
6efda038-9755-11e4-b981-feb7b39d48d6
6f9641bf-9755-11e4-b981-feb7b39d48d6
758c3e3e-9755-11e4-b981-feb7b39d48d6 

Les deux premiers UUID ont été générés le plus rapidement possible. Ils ne varient que dans les 3 derniers petits du premier bloc. Ce sont les bits les moins significatifs de l'horodatage, ce qui signifie que nous voulons les pousser à droite lorsque nous convertissons cela en un tableau d'octets indexables. Comme exemple de compteur, le dernier identifiant est le plus récent, mais l’algorithme de permutation du KCD le placerait avant le 3ème identifiant (3e avant ms, derniers octets du premier bloc).

L'ordre correct pour l'indexation serait:

1e497556eec5eb6... 
1e497556eec5f10... 
1e497556eec8ddc... 
1e497556eee30d0... 
1e497556efda038... 
1e497556f9641bf... 
1e49755758c3e3e... 

Voir cet article pour plus d'informations: http://mysql.rjweb.org/doc.php / uuid

*** remarquez que je ne sépare pas le nibble de version des 12 bits les plus élevés de l'horodatage. Ceci est le D nibble de votre exemple. Je viens de le jeter devant. Donc ma séquence binaire finit par être DEFG9ABC et ainsi de suite. Cela implique que tous mes UUID indexés commencent par le même nibble. L'article fait la même chose.

Pour ceux qui viennent de trébucher à ce sujet, il existe maintenant une alternative bien meilleure d'après les recherches de Percona.

Il consiste à réorganiser les fragments UUID pour une indexation optimale, puis à les convertir en fichiers binaires pour un stockage réduit.

Lisez l'article complet ici .

Je suggérerais d'utiliser les fonctions ci-dessous, car celles mentionnées par @ bigh_29 transforment mes aides en nouvelles (pour des raisons que je ne comprends pas). De plus, ces tests sont un peu plus rapides dans les tests que j'ai effectués sur mes tables. https://gist.github.com/damienb/159151

DELIMITER |

CREATE FUNCTION uuid_from_bin(b BINARY(16))
RETURNS CHAR(36) DETERMINISTIC
BEGIN
  DECLARE hex CHAR(32);
  SET hex = HEX(b);
  RETURN LOWER(CONCAT(LEFT(hex, 8), '-', MID(hex, 9,4), '-', MID(hex, 13,4), '-', MID(hex, 17,4), '-', RIGHT(hex, 12)));
END
|

CREATE FUNCTION uuid_to_bin(s CHAR(36))
RETURNS BINARY(16) DETERMINISTIC
RETURN UNHEX(CONCAT(LEFT(s, 8), MID(s, 10, 4), MID(s, 15, 4), MID(s, 20, 4), RIGHT(s, 12)))
|

DELIMITER ;

si vous avez une valeur char / varchar au format GUID standard, vous pouvez simplement l'enregistrer sous BINARY (16) à l'aide de la simple CAST (MyString AS BINARY16), sans toutes ces séquences époustouflantes de CONCAT + SUBSTR.

Les champs BINARY (16) sont comparés / triés / indexés beaucoup plus rapidement que les chaînes et prennent également deux fois moins d’espace dans la base de données

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top