Y a-t-il des inconvénients à utiliser un varchar générique (255) pour tous les champs de texte?

100

J'ai un contactstableau qui contient des domaines tels que postcode, first name, last name, town, country, phone numberetc, qui sont tous définis comme VARCHAR(255)même si aucun de ces domaines ne viendra jamais près d'avoir 255 caractères. (Si vous vous posez la question, c'est de cette façon parce que les migrations Ruby on Rails mappent les champs String VARCHAR(255)par défaut et je n'ai jamais pris la peine de le remplacer).

Étant donné que VARCHAR ne stockera que le nombre de caractères réels du champ (ainsi que la longueur du champ), y a-t-il un avantage distinct (performance ou autre) à utiliser, par exemple, VARCHAR(16)over VARCHAR(255)?

En outre, la plupart de ces champs ont des index sur eux. Une taille VARCHAR plus grande sur le champ affecte-t-elle la taille ou les performances de l'index?

Pour info, j'utilise MySQL 5.

Olly
la source
2
@ceejayoz, déclarant que la réponse acceptée est incorrecte sans expliquer pourquoi n'aide pas vraiment. Ce qui aggrave encore les choses, c'est que la réponse acceptée peut changer avec le temps et votre commentaire incitera les gens à penser que la nouvelle réponse acceptée est incorrecte.
Gili
1
@Gili a supprimé mon commentaire car le PO a apparemment changé son acceptation. Bons points, à l'avenir je vous indiquerai de quelle réponse je parle et pourquoi.
ceejayoz
Quelques autres réponses à cette question en double, stackoverflow.com/questions/1262174/…
James McMahon

Réponses:

129

Dans le stockage, il VARCHAR(255)est assez intelligent pour stocker uniquement la longueur dont vous avez besoin sur une ligne donnée, contrairement à CHAR(255)ce qui stockerait toujours 255 caractères.

Mais puisque vous avez tagué cette question avec MySQL, je mentionnerai une astuce spécifique à MySQL: lorsque les lignes sont copiées de la couche du moteur de stockage vers la couche SQL, les VARCHARchamps sont convertis en CHARpour gagner l'avantage de travailler avec des lignes de largeur fixe. Ainsi, les chaînes en mémoire sont remplies à la longueur maximale de votre VARCHARcolonne déclarée .

Lorsque votre requête génère implicitement une table temporaire, par exemple lors du tri ou GROUP BY, cela peut utiliser beaucoup de mémoire. Si vous utilisez beaucoup de VARCHAR(255)champs pour des données qui n'ont pas besoin d'être aussi longues, cela peut rendre la table temporaire très volumineuse.

Vous voudrez peut-être aussi savoir que ce comportement de «remplissage» signifie qu'une chaîne déclarée avec le jeu de caractères utf8 remplit jusqu'à trois octets par caractère même pour les chaînes que vous stockez avec un contenu à un octet (par exemple, les caractères ascii ou latin1). Et de même, le jeu de caractères utf8mb4 entraîne le remplissage de la chaîne à quatre octets par caractère en mémoire.

Ainsi, un VARCHAR(255)in utf8 stockant une chaîne courte comme "No opinion" prend 11 octets sur le disque (dix caractères de jeu de caractères inférieurs, plus un octet pour la longueur) mais cela prend 765 octets en mémoire, et donc dans des tables temporaires ou des résultats triés.

J'ai aidé les utilisateurs de MySQL qui, sans le savoir, ont fréquemment créé des tables temporaires de 1,5 Go et ont rempli leur espace disque. Ils avaient beaucoup de VARCHAR(255)colonnes qui stockaient en pratique des chaînes très courtes.

Il est préférable de définir la colonne en fonction du type de données que vous souhaitez stocker. Il présente des avantages pour appliquer les contraintes liées aux applications, comme d'autres l'ont mentionné. Mais il a les avantages physiques d'éviter le gaspillage de mémoire que j'ai décrit ci-dessus.

Il est difficile de savoir quelle est l'adresse postale la plus longue, bien sûr, c'est pourquoi de nombreuses personnes choisissent une VARCHARadresse longue qui est certainement plus longue que n'importe quelle adresse. Et 255 est habituel car c'est la longueur maximale de a VARCHARpour laquelle la longueur peut être codée avec un octet. C'était aussi la VARCHARlongueur maximale de MySQL antérieure à 5.0.

Bill Karwin
la source
6
J'ai toujours pensé que 255c'était utilisé pour que la longueur de la chaîne puisse tenir dans un seul octet
BlueRaja - Danny Pflughoeft
3
@BlueRaja: C'était probablement vrai pour les bases de données dont la structure de fichier interne encodait la longueur d'une chaîne en un seul octet, ou si elles encodaient des chaînes courtes en un seul octet. Mais ce n'est plus vrai pour la plupart des bases de données.
Bill Karwin le
7
@BlueRaja: InnoDB ne stocke pas la longueur du varchar suivant, il stocke une série de décalages de champ pour tous les champs de la ligne. Ces décalages de champ peuvent être de 1 octet si la taille de ligne totale est inférieure à 127 octets, ou bien 2 octets. Voir forge.mysql.com/wiki/MySQL_Internals_InnoDB
Bill Karwin
6
@BlueRaja: MyISAM (pour ceux qui l'utilisent encore) stocke les longueurs de varchar, et celles-ci peuvent être stockées sur 1 ou 2 octets. Cependant: "Lors de l'envoi d'une clé au gestionnaire pour index_read () ou records_in_range, nous utilisons toujours une longueur de 2 octets pour le VARCHAR afin de simplifier les choses." Voir forge.mysql.com/wiki/MySQL_Internals_MyISAM
Bill Karwin
1
une question - trier et grouper par sur n'importe quel champ ou le champ varchar lui-même?
Rohit Banga
24

Outre les considérations de taille et de performances liées à la définition de la taille d'un varchar (et peut-être plus important, car le stockage et le traitement deviennent moins chers chaque seconde), l'inconvénient d'utiliser varchar (255) «juste parce que» est une réduction de l'intégrité des données .

La définition de limites maximales pour les chaînes est une bonne chose à faire pour éviter que des chaînes plus longues que prévu n'entrent dans le SGBDR et ne provoquent des dépassements de mémoire tampon ou des exceptions / erreurs plus tard lors de la récupération et de l'analyse des valeurs de la base de données qui sont plus longues (plus d'octets) que prévu.

Par exemple, si vous avez un champ qui accepte des chaînes de deux caractères pour les abréviations de pays, vous n'avez aucune raison concevable d'attendre de vos utilisateurs (dans ce contexte, les programmeurs) qu'ils saisissent les noms de pays complets. Puisque vous ne voulez pas qu'ils entrent "Antigua-et-Barbuda" (AG) ou "Heard Island et McDonald Islands" (HM), vous ne l'autorisez pas au niveau de la base de données. En outre, il est probable que certains programmeurs ont pas encore RTFMed la documentation de conception ( qui existe sûrement ) de ne pas savoir faire cela.

Définissez le champ pour accepter deux caractères et laissez le SGBDR le traiter (soit gracieusement en tronquant, soit sans grâce en rejetant leur SQL avec une erreur).

Exemples de données réelles qui n'ont aucune raison de dépasser une certaine longueur:

  • Les codes postaux canadiens sont au format A1A1A1 et comportent toujours 6 caractères, même pour le Père Noël (6 caractères exclut l'espace qui peut être spécifié pour la lisibilité).
  • adresses e-mail - jusqu'à 64 octets avant le @, jusqu'à 255 octets après. Jamais plus, de peur de casser Internet.
  • Les numéros de téléphone nord-américains ne comportent jamais plus de 10 chiffres (à l'exclusion du code du pays).
  • Les ordinateurs exécutant (versions récentes de) Windows ne peuvent pas avoir de noms d'ordinateur de plus de 63 octets , bien que plus de 15 ne soient pas recommandés et endommageront votre batterie de serveurs Windows NT.
  • Les abréviations d'état sont de 2 caractères (comme les codes de pays examinés ci-dessus)
  • Les numéros de suivi UPS comportent 18, 12, 11 ou 9 caractères. Les nombres à 18 caractères commencent par "1Z" et les nombres à 11 caractères commencent par "T", ce qui vous fait vous demander comment ils livrent tous ces paquets s'ils ne connaissent pas la différence entre les lettres et les chiffres.

Etc...

Prenez le temps de réfléchir à vos données et à leurs limites. Si vous êtes architecte, développeur ou programmeur, c'est votre travail , après tout.

En utilisant un varchar (n) au lieu de varchar (255), vous éliminez le problème où les utilisateurs (utilisateurs finaux, programmeurs, autres programmes) entrent des données inopinément longues qui reviendront hanter votre code plus tard.

Et je n'ai pas dit que vous ne devriez pas également implémenter cette restriction dans le code de logique métier utilisé par votre application.

shufler
la source
5
Les codes postaux canadiens comportent en fait 7 chiffres, l'espace au milieu est important et devrait figurer sur les étiquettes postales. Les numéros de téléphone nord-américains peuvent comporter plus de 10 chiffres s'il y a une extension. Si vous n'êtes pas en mesure de stocker des extensions de numéro de téléphone, 10 chiffres conviennent, mais vous le regretterez probablement.
Kibbee le
3
Il y a certainement lieu d'être restrictif pour l'intégrité des données. Cependant, il est toujours facile d'être trop restrictif. Imposer des restrictions pour les données que vous contrôlez et imposer des restrictions sensées pour les exigences de données que vous ne pouvez pas contrôler. Votre numéro de téléphone et les restrictions d'e-mail sont raisonnables (en supposant que vous ne vous internationalisez jamais). Votre exigence qui dit que la troncature d'un code de pays à deux caractères est la chose "gracieuse" est insensée. Vous savez qu'il y a eu une erreur, ne tronquez pas et n'acceptez pas. Si vous tronquez, il y a une probabilité extrêmement élevée que vous vous retrouviez avec un code de pays incorrect.
coderjoe
La plupart des applications auront la validation des données avant de les envoyer à la base de données ...
Cobby
2
Sûr. Plus. Mais je pense qu'ici vous supposez qu'un développeur qui développe une nouvelle application pour une base de données existante est conscient des restrictions sur les données (nous ne sommes pas tous experts sur tous les types de données et sur la façon dont elles sont implémentées dans chaque base de données ). Ce n'est pas parce que vous pouvez valider les données de votre application que vous l'avez fait.
shufler
3
the design documentation (which surely exists)Hah. : D
Camilo Martin
14

Je suis d'accord. Une attention particulière aux détails est une douleur dans le cou et a une valeur limitée.

Il était une fois, le disque était une denrée précieuse et nous avions l'habitude de suer les balles pour l'optimiser. Le prix du stockage a été divisé par 1 000, ce qui rend le temps passé à presser chaque octet moins précieux.

Si vous n'utilisez que des champs CHAR, vous pouvez obtenir des lignes de longueur fixe. Cela peut économiser une reformulation réelle du disque si vous avez choisi des tailles précises pour les champs. Vous pouvez obtenir des données plus denses (moins d'E / S pour les analyses de table) et des mises à jour plus rapides (plus facile à localiser les espaces ouverts dans un bloc pour les mises à jour et les insertions).

Cependant, si vous surestimez vos tailles ou si vos tailles de données réelles sont variables, vous finirez par perdre de l'espace avec les champs CHAR. Les données seront moins densément compactées (ce qui entraînera plus d'E / S pour les grandes récupérations).

En règle générale, les avantages en termes de performances de la tentative de mettre une taille sur des champs variables sont mineurs. Vous pouvez facilement comparer en utilisant VARCHAR (255) par rapport à CHAR (x) pour voir si vous pouvez mesurer la différence.

Cependant, parfois, j'ai besoin de fournir un indice «petit», «moyen», «grand». J'utilise donc 16, 64 et 255 pour les tailles.

S.Lott
la source
13

De nos jours, je ne peux pas imaginer que cela compte vraiment plus.

L'utilisation de champs de longueur variable entraîne une surcharge de calcul, mais avec les excès des processeurs actuels, cela ne vaut même pas la peine d'être pris en compte. Le système d'E / S est si lent que les coûts de calcul pour gérer les varchars sont effectivement inexistants. En fait, le prix d'un varchar est probablement un gain net sur la quantité d'espace disque économisé en utilisant des champs de longueur variable sur des champs de longueur fixe. Vous avez probablement une plus grande densité de lignes.

Maintenant, la complexité des champs varchar est que vous ne pouvez pas localiser facilement un enregistrement via son numéro d'enregistrement. Lorsque vous avez une taille de ligne de longueur fixe (avec des champs de longueur fixe), il est trivial de calculer le bloc de disque vers lequel pointe un identifiant de ligne. Avec une taille de ligne de longueur variable, ce genre de sortie par la fenêtre.

Donc, maintenant, vous devez maintenir une sorte d'index de numéro d'enregistrement, comme toute autre clé primaire, OU vous devez créer un identifiant de ligne robuste qui encode les détails (tels que le bloc, etc.) dans l'identifiant. Si vous faites cela, cependant, l'ID devrait être recalculé si jamais la ligne est déplacée sur un stockage persistant. Ce n'est pas grave, il suffit de réécrire toutes les entrées d'index et de s'assurer que vous a) ne l'exposez jamais au consommateur ou b) n'affirmez jamais que le nombre est fiable.

Mais puisque nous avons des champs varchar aujourd'hui, la seule valeur de varchar (16) par rapport à varchar (255) est que la base de données appliquera la limite de 16 caractères sur varchar (16). Si le modèle de base de données est censé être réellement représentatif du modèle de données physique, alors la longueur des champs peut être intéressante. Si, cependant, il s'agit simplement d'un "stockage" plutôt que d'un "modèle ET stockage", il n'y a aucun besoin.

Ensuite, vous devez simplement discerner entre un champ de texte indexable (tel que varchar) et quelque chose qui ne l'est pas (comme un champ de texte ou CLOB). Les champs indexables ont tendance à avoir une limite de taille pour faciliter l'index, contrairement aux champs CLOB (dans des limites raisonnables).

Will Hartung
la source
5

D'après mon expérience, si vous autorisez un type de données de 255 caractères, un utilisateur stupide (ou un testeur expérimenté) le remplira.

Ensuite, vous rencontrez toutes sortes de problèmes, y compris l'espace que vous accordez à ces champs dans les rapports et les affichages à l'écran dans votre application. Sans parler de la possibilité de dépasser la limite par ligne pour les données de votre base de données (si vous aviez plus de quelques-uns de ces 255 champs de caractères).

Il est beaucoup plus facile de choisir une limite raisonnable au début, puis de l'appliquer via l'application et la base de données.

BradC
la source
0

C'est une bonne pratique de n'allouer qu'un peu plus ce dont vous avez besoin. Les numéros de téléphone n'iraient jamais aussi loin.

Une des raisons est que si vous ne validez pas contre des entrées volumineuses, quelqu'un utilisera sans aucun doute tout ce qu'il y a. Ensuite, vous pourriez manquer d'espace dans votre rangée. Je ne suis pas sûr de la limite de MySQL, mais 8060 est la taille maximale des lignes dans MS SQL.

Un défaut plus normal serait de 50 imho, puis augmenterait là où le besoin le prouve.

Colombe
la source
Merci. Je suis tout à fait d'accord pour dire que c'est une bonne pratique. C'est l'aspect performance sur lequel j'aimerais vraiment avoir des éclaircissements
Olly
0

Dans un contexte mysql, cela peut devenir important lorsque vous travaillez avec des index sur lesdites colonnes varchar, car mysql a un max. limite de 767 octets par ligne d'index.

Cela signifie que lorsque vous ajoutez un index sur plusieurs colonnes varchar 255, vous pouvez atteindre cette limite assez rapidement / encore plus rapidement sur les colonnes utf8 ou utf8mb4, comme indiqué dans les réponses ci-dessus

staabm
la source