web-dev-qa-db-fra.com

Quel est l'impact sur les performances de l'utilisation de CHAR vs VARCHAR sur un champ de taille fixe?

J'ai une colonne indexée qui stocke un hachage MD5. Ainsi, la colonne stockera toujours une valeur de 32 caractères. Pour une raison quelconque, cela a été créé en tant que varchar plutôt que char. Vaut-il la peine de migrer la base de données pour la convertir en caractère? C'est dans MySQL 5.0 avec InnoDB.

60
Jason Baker

Une question similaire a été posée avant

Implications des performances des tailles MySQL VARCHAR

Voici l'extrait de ma réponse

Vous devez comprendre les compromis de l'utilisation de CHAR vs VARCHAR

Avec les champs CHAR, ce que vous allouez est exactement ce que vous obtenez. Par exemple, CHAR (15) alloue et stocke 15 octets, quelle que soit la façon dont vous placez les caractères dans le champ. La manipulation des chaînes est simple et directe car la taille du champ de données est totalement prévisible.

Avec les champs VARCHAR, vous obtenez une histoire complètement différente. Par exemple, VARCHAR (15) alloue en fait dynamiquement jusqu'à 16 octets, jusqu'à 15 pour les données et, au moins, 1 octet supplémentaire pour stocker la longueur des données. Si vous avez la chaîne "bonjour" à stocker qui prendra 6 octets, pas 5. La manipulation de chaîne doit toujours effectuer une certaine forme de vérification de longueur dans tous les cas.

Le compromis est plus évident lorsque vous faites deux choses: 1. Stocker des millions ou des milliards de lignes 2. Indexer les colonnes qui sont CHAR ou VARCHAR

TRADEOFF # 1 De toute évidence, VARCHAR détient l'avantage car les données de longueur variable produiraient des lignes plus petites et, par conséquent, des fichiers physiques plus petits.

TRADEOFF # 2 Étant donné que les champs CHAR nécessitent moins de manipulation de chaînes en raison de largeurs de champ fixes, les recherches d'index sur le champ CHAR sont en moyenne 20% plus rapides que celles des champs VARCHAR. Ce n'est pas une conjecture de ma part. Le livre MySQL Database Design and Tuning a réalisé quelque chose de merveilleux sur une table MyISAM pour le prouver. L'exemple du livre a fait quelque chose comme ceci:

ALTER TABLE tblname ROW_FORMAT=FIXED;

Cette directive oblige tous les VARCHAR à se comporter comme des CHAR. Je l'ai fait lors de mon précédent travail en 2007 et j'ai pris une table de 300 Go et accéléré les recherches d'index de 20%, sans rien changer d'autre. Cela a fonctionné comme publié. Cependant, il a produit une table presque double, mais cela revient simplement au compromis n ° 1.

Vous pouvez analyser les données stockées pour voir ce que MySQL recommande pour la définition des colonnes. Exécutez simplement ce qui suit sur n'importe quelle table:

SELECT * FROM tblname PROCEDURE ANALYSE();

Cela traversera la table entière et recommandera des définitions de colonne pour chaque colonne en fonction des données qu'elle contient, des valeurs de champ minimales, des valeurs de champ maximales, etc. Parfois, il suffit de faire preuve de bon sens lors de la planification de CHAR vs VARCHAR. Voici un bon exemple:

Si vous stockez des adresses IP, le masque d'une telle colonne est au maximum de 15 caractères (xxx.xxx.xxx.xxx). Je sauterais directement à CHAR(15) en un clin d'œil parce que la longueur des adresses IP ne variera pas beaucoup et la complexité supplémentaire de la manipulation des chaînes contrôlée par un octet supplémentaire. Vous pouvez toujours faire une PROCEDURE ANALYSE() contre une telle colonne. Il peut même recommander VARCHAR. Mon argent serait toujours sur CHAR sur VARCHAR dans ce cas.

Les problèmes CHAR vs VARCHAR ne peuvent être résolus que par une bonne planification. Un grand pouvoir s'accompagne d'une grande responsabilité (cliché mais vrai).

MISE À JOUR

En ce qui concerne MD5, le calcul de strlen en interne doit être éliminé lors du changement de format de ligne entier. Il ne serait pas nécessaire de modifier la définition du champ.

Si la clé MD5 est la seule VARCHAR présente, j'irais pour elle et convertirais le format de ligne du tableau en fixe . S'il y a un nombre important d'autres champs VARCHAR présents, ils en bénéficieraient également. En échange, le tableau s'élargirait à environ le double de sa taille. Mais les requêtes devraient accélérer d'environ 20% de plus sans réglage supplémentaire.

57
RolandoMySQLDBA

Il semble que vous économiserez 1 octet par valeur ou environ 3% en convertissant en char. Cela ne vaut probablement pas la peine si vous stockez MD5 dans un hex de toute façon - vous pourriez économiser 50% en utilisant un binary à la place.

Merci à Ovais (voir les commentaires) d'avoir souligné que char(32) peut tiliser beaucoup plus de 32 octets si vous utilisez un jeu de caractères multi-octets.

Merci à Rick James d'avoir souligné que vous devez utiliser la fonction unhex pour convertir la chaîne hexadécimale en binaire:

create table foo(bar varbinary(100));
insert into foo(bar) values(md5('a')); 
insert into foo(bar) values(unhex(md5('a'))); 
select length(bar) from foo;
 | longueur (bar) | 
 | ----------: | 
 | 32 | 
 | 16 | 

db <> violon ici

Cela ne vaut pas la peine de changer à mon avis. Si vous regardez la documentation ici, elle devrait illustrer la différence entre les deux. Dans votre scénario d'utilisation, l'un n'offre pas vraiment d'avantages significatifs par rapport à l'autre, sauf si vous êtes vraiment préoccupé par la surcharge supplémentaire liée à la taille des lignes.

http://dev.mysql.com/doc/refman/5.0/en/char.html

Notez également le premier commentaire sur la documentation à laquelle je renvoie ci-dessus ... "CHAR n'accélérera votre accès que si l'enregistrement entier est de taille fixe. Autrement dit, si vous utilisez un objet de taille variable, vous pourriez tout aussi bien les faire tous taille variable. Vous ne gagnez pas de vitesse en utilisant un CHAR dans une table qui contient également un VARCHAR "

15
RThomas