VARCHAR vs CHAR : quelles différences de perfs?

VARCHAR vs CHAR : quelles différences de perfs? - SQL/NoSQL - Programmation

Marsh Posté le 22-08-2006 à 15:51:50    

Bonjour,
 
Je sais que CHAR est plus rapide en lecture que VARCHAR. Cependant, j'aurais voulu savoir dans quelle mesure CHAR était plus rapide. En effet, j'ai des objets auquels sont liés des attributs. Or, l'enregistrement d'un attribut est constitué :
- d'un ID (mediumint)
- d'un nom (chaîne)
- d'une valeur (chaîne)
- d'un type (tinyint)
Le nom et la valeur sont des chaînes de taille variable n'excédant pas 255 caractères et un objet est constitué d'environ 400 attributs. Je me demandais donc si ça valait le coût de stocker le nom et la valeur sous la forme de CHAR(255) afin d'accélérer le chargement d'un objet (au détriement certes de l'espace de stockage)? Merci de votre aide :jap:
 
ps : je ne sais pas si ça change qq chose au pb, mais j'utilise MySQL 5.

Reply

Marsh Posté le 22-08-2006 à 15:51:50   

Reply

Marsh Posté le 22-08-2006 à 17:24:32    

Pour savoir si CHAR est plus rapide que VARCHAR, le mieux est de faire des tests, avec un jeu d'essai réaliste.
 
Personnellement, je pense que la différence sera de l'ordre de quelques millièmes de secondes en faveur de la solution avec le VARCHAR, car il y a moins d'octets à transporter dans la moyenne des cas.
 
Le CHAR est conseiller pour les champs qui font un octet de longueur, ou pour les champs qui contiennent des caractères binaires spéciaux tels que le 0 binaire, ou le retour à la ligne, qui peuvent être interprétés comme des fins de champ s'il étaient en VARCHAR.
 
Une amélioration possible serait d'employer un INT au lieu du TINYINT car l'ordinateur travaille avec des entiers et fait un masquage pour ne montrer que la partie tinyint au programme. Mais le gain est de l'ordre que quelques millièmes de seconde car le masquage est rapide, donc cela ne vaut pas le coup.
 
Ce qui compte surtout pour les performances, c'est d'avoir des index adéquats, des requêtes où il n'y a pas trop de OR ni trop de produits cartésiens, et un réseau qui ne soit pas trop lent, si c'est en réseau.

Message cité 1 fois
Message édité par olivthill le 22-08-2006 à 17:25:55
Reply

Marsh Posté le 22-08-2006 à 18:33:07    

merci pour le coup du masquage, je ne savais pas...

Reply

Marsh Posté le 22-08-2006 à 18:39:19    

olivthill a écrit :

Le CHAR est conseiller pour les champs qui font un octet de longueur, ou pour les champs qui contiennent des caractères binaires spéciaux tels que le 0 binaire


 
comme boolean ? [:cupra]

Reply

Marsh Posté le 22-08-2006 à 19:24:33    

ça dépend de ton SGBDR
 

Citation :

Tip:  There are no performance differences between these three types, apart from the increased storage size when using the blank-padded type. While character(n) has performance advantages in some other database systems, it has no such advantages in PostgreSQL. In most situations text or character varying should be used instead.

Reply

Marsh Posté le 23-08-2006 à 11:09:35    

mon sgbdr, c'est mysql 5.0.22. Donc, a priori, j'ai plutôt intérêt à utiliser varchar, ça va peut influer sur les perfs.

Reply

Marsh Posté le 23-08-2006 à 11:52:38    

En fait, pour faire ton choix, le mieux est de comprendre comment ça se passe pour récupérer les données.
 
Pour un CHAR, comme elles sont de longueur fixe, leur position est située toujours au même endroit dans ton enregistrement, donc, il y a accès direct. Contrairement au VARCHAR, qui va lui nécessiter à MySQL d'aller voir dans les dans les colonnes de taille variable et de faire un petit calcul pour trouver le bon décalage (offset). Donc, ce sera nécessairement plus lent (du point de vue localisation de la donnée)
 
Mais de toute manière, je dirais d'une manière générale:
- Si tes enregistrements ont tous la même longueur ou alors "presque" tous (cad qu'il peut y en en avoir quelques uns qui ont un peu en dessous de la longueur maximale), utilise du CHAR
- Dans tous les autres cas, prends du VARCHAR, ce sera plus intéressant en terme d'espace requis pour le stockage (et donc, finalement, en taille de données récupérées et donc, en fin de compte, s'il y a beaucoup d'enregistrements, en terme de vitesse d'exécution)
 
Pour ma part, je ne réserve le CHAR que pour les champs de taille fixe (souvent des champs dit "techniques", tel que des champs de bits, ou alors de clefs à taille fixe, etc...)
 
Dans ton cas, ce sera VARCHAR(255).
 
PS: Par contre, ne mets pas une longueur de 256 ou plus, car ça nécessitera encore 1 octet de plus par valeur... longueur stocée sur 2 octets au lieu de 1)

Reply

Marsh Posté le 23-08-2006 à 12:06:23    

ok, bon ça confirme mon choix initial du varchar. Merci de votre expertise :jap:

Reply

Marsh Posté le 23-08-2006 à 12:25:18    

Pour reprendre, il est impératif d'utiliser CHAR dans les cas suivants :
- Identifiant
- Code (EAN13, ISBN, etc.)
- Longueur = 1
- Mises à jours intensives
 
Pour le reste, le VARCHAR est en effet légèrement plus lent que le CHAR à cause du problème d'offset. Cependant, ce n'est pas tout à fait vrai.
Généralement, le SGBD réserve de la place au varchar, c'est à dire que si tu décare un varchar(255) et que tu écrit 2 caractères dedans, il y a de grande chances que le SGBD réserve par exemple 100 caractères supplémentaire sur le disque au cas où il doive changer de taille. En effet, le problème, c'est que s'il n'y a plus de place, il faut alors de longues oppérations sur le disque pour tout re-décaller afin de stocker la nouvelle valeur. C'est pourquoi il faut TOUJOURS mettre les champs de taille non fixe à la fin de la déclaration de la table.
Un champ "blob/clob/text/image/etc." a une taille fixe (c'est un pointeur).
Un champ "numeric/decimal" n'a pas une taille fixe !
 
Ainsi :
 
create table toto as (
key as integer primary key, -- fixe
code as char(5), -- fixe
datcre as datetime, -- fixe
volume as float, -- fixe
longdesc as ntext, -- fixe
prix as decimal(12,2), -- fixe mais changement de taille très rare
nom as nvarchar(50)) -- fixe avec grand risque de changement de taille

Reply

Marsh Posté le 23-08-2006 à 14:02:12    

merci de ces précisions. Je ne savais pas ce détail, le coup des champs non fixes à la fin.

Reply

Marsh Posté le 23-08-2006 à 14:02:12   

Reply

Marsh Posté le 23-08-2006 à 14:41:32    

MagicBuzz a écrit :


C'est pourquoi il faut TOUJOURS mettre les champs de taille non fixe à la fin de la déclaration de la table.


 
Tu es certain de ce que tu dis?
 
Sous MySQL, je ne sais pas, il faudrait que je checke (qu ce soit avec les tables de type MyISAM ou de type InnoDb) mais sous SQL Server, je peux t'assurer que quelle que soit la déclaration de ta table et l'ordre dans lequel tu spécifies tes colonnes, le SGDB met automatiquement les champs de taille variable à la fin, et donc, inutile de toucher au design de ses créations de table (c'est toujours plus agréable lorsque les champs apparaissent dans l'ordre que l'on souhaite lors des requêtes naturelles du type "SELECT * FROM" )


Message édité par Yoyo@ le 23-08-2006 à 14:45:28
Reply

Marsh Posté le 23-08-2006 à 14:47:56    

dans la mesure du possible : moins je fais confiance au bignou, et moins le bignou fait de connerie ;)
 
en fait, le principal souci, c'est que parfois, pour diverses raison, le sgbd sait plus trop où il en est, et fait bêtement ce que tu lui dit sans réarranger à sa sauce. ça arrive souvent par exemple quand tu executes une requête, parfois, pour la même requête, l'optimiseur par en live et parfois il marche.
donc si tu lui mâches le boulot avant, t'as moins de risques pour qu'il te fasse n'importe quoi ;)
 
je rappelle, j'ai bossé avec Oracle 8.0.5, depuis je n'ai plus la moindre confiance en n'importe quel SGBD
 
ps: et c'est mal de travailler en direct sur les tables :o dans toutes les bases que je fais, j'ai "forbidden everything for everyone" sur toutes les tables.
et des vues et PS qui viennent taper dans les tables. c'est plus sexy, et surtout, ça évite de faire des conneries ;)

Message cité 1 fois
Message édité par MagicBuzz le 23-08-2006 à 14:48:43
Reply

Marsh Posté le 23-08-2006 à 14:57:10    

MagicBuzz a écrit :

dans la mesure du possible : moins je fais confiance au bignou, et moins le bignou fait de connerie ;)
en fait, le principal souci, c'est que parfois, pour diverses raison, le sgbd sait plus trop où il en est, et fait bêtement ce que tu lui dit sans réarranger à sa sauce. ça arrive souvent par exemple quand tu executes une requête, parfois, pour la même requête, l'optimiseur par en live et parfois il marche.
donc si tu lui mâches le boulot avant, t'as moins de risques pour qu'il te fasse n'importe quoi ;)


 
Pour l'optimiseur de requête, sou MySQL, ça arrive effectivement qu'il fasse n'importe quoi (mais ça reste rare, et les conséquences, à part une vitesse d'exécution diminuée, ne vont pas plus loin). D'ailleurs, l'otpimiseur de requête MySQL n'est pas des plus performants et des plus futés, mais d'un autre côté, ce SGBD est tellement rapide pour récupérer les données, même sans utiliser le bon index...
 
Mais concernant la structure des tables, ce serait grave si de fois, le SGBD se mettait à faire n'importe quoi. Par exemple, dals le cas de SQL Server, si jamais les colonnes à largeur variables sont systématiquement mises à la fin, et vu comment les pages de données sont golées, il est STRICTEMENT IMPOSSIBLE qu'il en soit autrement, donc, le SGBD ne risque pas de s'emmêler les pinceaux (ou alors, ça voudrait dire que la base est corrompue)
 
Et je pense que ce doit être pareil pour MySQL (mais il faut que je checke, car ça m'intéresse de savoir)
 
En tout cas, sinon, chui d'accord avec toi pour l'utilisation des CHAR.
 
Donc, notre ami se doit d'uitliser des VARCHAR.


Message édité par Yoyo@ le 23-08-2006 à 14:57:42
Reply

Marsh Posté le 23-08-2006 à 15:00:53    

mais moi je fais quand même pas confiance au SGBD, même s'il ne peut pas faire autrement que de marcher :D
 
j'ai vu tellement d'inepties avec Oracle...
 
le truc fun :
 
select * from matable
=> ça commence à retourner des lignes... et au bout de quelques secondes, proutch, sql+ se ferme.
 
tu rouvres. tu relances la requête. ctrl+c.
=> t'as bien le début et t'as pas planté.
 
select count(*) from matable
=> super ça marche
 
select id from matable
=> super, ça marche
 
select prix from matable
=> proutch
 
hmmm
desc matable
 
ok, prix est un type number
 
select to_char(prix) from matable
=> ok
 
hmmm
tu inspectes les lignes une a une...
 
et au milieux des prix, tu trouves un truc style "10 F"
 
forcément, si Oracle arrive à stocker des strings dans des number...
 
après un alter en varchar, une modif de la valeur, et un nouvel alter en number, ça a résolu le problème
 
mais depuis, je ne fais plus une miette de confiance à un SGBD :o


Message édité par MagicBuzz le 23-08-2006 à 15:05:04
Reply

Marsh Posté le 23-08-2006 à 15:05:48    

Je pense que tu as dû faire une très mauvaise expérience avec cet Oracle pour en arriver à ce niveau de méfiance...
 
Edit: j'avais pas vu la fin de ton post. Seule la première phrase était apparue...
 
En effet! Peut être que le F de "10 F" venat du fait que le SGBD t'a pris pou un vieux français parlant encore en Francs?? :D


Message édité par Yoyo@ le 23-08-2006 à 15:08:45
Reply

Marsh Posté le 23-08-2006 à 15:06:20    

vivi, cf mon edit ;)

Reply

Marsh Posté le 23-08-2006 à 15:09:32    

MagicBuzz a écrit :

vivi, cf mon edit ;)


 
Ahaha, donc, tu avais édité! Et moi qui pensais que le MySQL du forum hfr n'avait pas retourné l'intégralité de ton post... (et seulement la première ligne), un peu comme ton SQLPlus !


Message édité par Yoyo@ le 23-08-2006 à 15:10:13
Reply

Marsh Posté le 23-08-2006 à 15:13:09    

pour le 10 F, nan, ça date de toute façon du franc ;)
il s'était retrouvé dans la colonne a priori lors d'un sql loader qu'oracle n'a pas été foutu de contrôler correctement.

Reply

Marsh Posté le 23-08-2006 à 15:18:47    

Ca doit vraiment foutre les boules une base qui devient corrompue de la sorte...
 
Et encore, dans ton cas, tu as réussi à t'en sortir, mais ça aurait pu être pire...

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed