Meilleures pratiques pour la longueur des colonnes varchar SQL [fermé]

289

Chaque fois que l'on met en place une nouvelle table SQL ou ajoute une nouvelle varcharcolonne à une table existante, je me demande une chose: quelle est la meilleure valeur pour le length.

Donc, disons, vous avez une colonne appelée namede type varchar. Vous devez donc choisir la longueur. Je ne peux pas penser à un nom> 20 caractères, mais vous ne saurez jamais. Mais au lieu d'utiliser 20, j'arrondis toujours au nombre 2 ^ n suivant. Dans ce cas, je choisirais 32 comme longueur. Je le fais, car du point de vue d'un informaticien, un nombre 2 ^ n evenme semble plus que d'autres nombres et je suppose simplement que l'architecture en dessous peut gérer ces nombres légèrement mieux que d'autres.

Par contre, le serveur MSSQL, par exemple, définit la valeur de longueur par défaut sur 50, lorsque vous choisissez de créer une colonne varchar. Cela me fait réfléchir. Pourquoi 50? est-ce juste un nombre aléatoire, ou basé sur la longueur moyenne d'une colonne, ou quoi?

Il se pourrait également - ou probablement - que différentes implémentations de serveurs SQL (comme MySQL, MSSQL, Postgres, ...) aient différentes valeurs de longueur de colonne optimales.

esskar
la source

Réponses:

238

Aucun SGBD que je connais n'a d '"optimisation" qui rendrait un VARCHARavec une 2^nlongueur plus performant qu'un avec une maxlongueur qui n'est pas une puissance de 2.

Je pense que les premières versions de SQL Server traitaient en réalité une VARCHARlongueur 255 différemment d'une longueur maximale plus élevée. Je ne sais pas si c'est toujours le cas.

Pour presque tous les SGBD, le stockage réel requis est uniquement déterminé par le nombre de caractères que vous y insérez, et non par la maxlongueur que vous définissez. Donc, du point de vue du stockage (et probablement aussi des performances), cela ne fait aucune différence que vous déclariez une colonne comme VARCHAR(100)ou VARCHAR(500).

Vous devriez voir la maxlongueur fournie pour une VARCHARcolonne comme une sorte de contrainte (ou de règle commerciale) plutôt que comme une chose technique / physique.

Pour PostgreSQL, la meilleure configuration consiste à utiliser textsans restriction de longueur et CHECK CONSTRAINTqui limite le nombre de caractères à tout ce dont votre entreprise a besoin.

Si cette exigence change, la modification de la contrainte de vérification est beaucoup plus rapide que la modification de la table (car la table n'a pas besoin d'être réécrite)

La même chose peut être appliquée pour Oracle et d'autres - dans Oracle, ce serait VARCHAR(4000)au lieu de textbien.

Je ne sais pas s'il y a une différence de stockage physique entre VARCHAR(max)et par exemple VARCHAR(500)dans SQL Server. Mais apparemment, il y a un impact sur les performances lors de l'utilisation varchar(max)par rapport à varchar(8000).

Voir ce lien (publié par Erwin Brandstetter en tant que commentaire)

Modifier 2013-09-22

Concernant le commentaire de bigown:

Dans les versions Postgres antérieures à 9.2 (qui n'étaient pas disponibles lorsque j'ai écrit la réponse initiale), une modification de la définition de colonne a réécrit tout le tableau, voir par exemple ici . Depuis la version 9.2, ce n'est plus le cas et un test rapide a confirmé que l'augmentation de la taille des colonnes pour un tableau de 1,2 million de lignes ne prenait en effet que 0,5 seconde.

Pour Oracle, cela semble également être vrai, à en juger par le temps qu'il faut pour modifier la varcharcolonne d' une grande table . Mais je n'ai pu trouver aucune référence pour cela.

Pour MySQL, le manuel dit " Dans la plupart des cas, ALTER TABLEcrée une copie temporaire de la table d'origine ". Et mes propres tests confirment que: exécuter un ALTER TABLEsur une table avec 1,2 million de lignes (le même que dans mon test avec Postgres) pour augmenter la taille d'une colonne a pris 1,5 minute. Dans MySQL, cependant, vous ne pouvez pas utiliser la "solution de contournement" pour utiliser une contrainte de vérification pour limiter le nombre de caractères dans une colonne.

Pour SQL Server, je n'ai pas pu trouver de déclaration claire à ce sujet, mais le temps d'exécution pour augmenter la taille d'une varcharcolonne (encore une fois le tableau de 1,2 million de lignes ci-dessus) indique qu'aucune réécriture n'a lieu.

Modifier 2017-01-24

Semble que j'avais (au moins partiellement) tort sur SQL Server. Voir cette réponse d'Aaron Bertrand qui montre que la longueur déclarée d'une nvarcharou de varcharcolonnes fait une énorme différence pour la performance.

un cheval sans nom
la source
34
En fait, il y a une différence entre VARCHAR (255) et VARCHAR (500), même si vous mettez 1 caractère dans cette colonne. La valeur ajoutée à la fin de la ligne sera un entier qui stocke la longueur réelle des données stockées. Dans le cas de VARCHAR (255), ce sera un entier de 1 octet. Dans le cas de VARCHAR (500), ce sera 2 octets. c'est une petite différence, mais il faut en être conscient. Je n'ai pas de données sur la façon dont cela peut affecter les performances, mais je suppose qu'il est si petit qu'il ne vaut pas la peine d'être étudié.
NB
1
@ NB: c'est à cela que je faisais référence pour la valeur 255 "magique" de SQL Server. Merci pour la clarification.
a_horse_with_no_name
4
@NB De quel SGBDR parlez-vous? Serveur SQL? Il y a un effet sur les performances. [N] VARCHAR (max) fonctionne légèrement plus lentement que [N] VARCHAR (n). J'ai récemment été référé à ce site . La même chose n'est pas vraie pour PostgreSQL pour tout ce que je sais.
Erwin Brandstetter
@ErwinBrandstetter: Merci pour le lien. On dirait qu'il ressemble varchar(max)probablement plus à celui d'OracleCLOB
a_horse_with_no_name
1
Changer la longueur de varchar ne réécrit pas la table. Il suffit de vérifier la longueur de la contrainte par rapport à la table entière exactement comme CHECK CONSTRAINT. Si vous augmentez la longueur, il n'y a rien à faire, juste la prochaine insertion ou les mises à jour accepteront une plus grande longueur. Si vous diminuez la longueur et que toutes les lignes passent la nouvelle contrainte plus petite, Pg n'entreprend aucune action supplémentaire pour permettre aux prochaines insertions ou mises à jour d'écrire uniquement la nouvelle longueur.
Maniero
69

VARCHAR(255)et VARCHAR(2)prenez exactement la même quantité d'espace sur le disque! Donc, la seule raison de le limiter est si vous avez un besoin spécifique pour qu'il soit plus petit. Sinon, faites-les tous 255.

Plus précisément, lors du tri, une colonne plus grande prend plus d'espace, donc si cela nuit aux performances, vous devez vous en préoccuper et les rendre plus petites. Mais si vous ne sélectionnez qu'une seule ligne dans ce tableau, vous pouvez simplement les faire toutes 255 et cela n'aura pas d'importance.

Voir: Quelles sont les tailles optimales de varchar pour MySQL?

Ariel
la source
7
Pourquoi ne pas les faire tous VARCHAR(MAX)? L'espace n'est pas la seule considération lors de la modélisation d'une base de données. Le domaine que vous modélisez doit générer les types de données et les tailles.
Odé
6
@Oded VARCHAR(MAX)n'est pas identique à varchar(255)ou varchar(65535)- varchar max est un type de type de textdonnées. Et à votre point - s'il savait ce que le «domaine qu'il modélisait», il ne poserait pas cette question. De toute évidence, il ne sait pas quelle sera la taille de ses données, et je le rassure: le fait de le faire en taille réelle ne fait rien.
Ariel
4
@Ariel: Il y a aussi des problèmes et des limitations sur les index à considérer. Vous ne pouvez pas avoir d' (a,b,c,d)index lorsque les quatre colonnes le sont VARCHAR(255).
ypercubeᵀᴹ
@ypercube C'est vrai, si vos colonnes ont besoin d'un index, vous devez être plus prudent avec les tailles. Mais la plupart des colonnes n'ont pas besoin d'un index, donc la plupart du temps, vous n'avez pas à vous en préoccuper.
Ariel
Je pense que si nous connaissons la valeur exacte, je préfère utiliser char. En attendant, s'il est toujours prédictif, j'utilise varchar et je garde 255 car c'est une allocation de mémoire dynamique, donc ne vous inquiétez pas de la taille qui sera prise
Faris Rayhan
54

Chaque fois que je configure une nouvelle table SQL, je ressens la même chose à propos de 2 ^ n étant plus "pair" ... mais pour résumer les réponses ici, il n'y a pas d'impact significatif sur l'espace de stockage simplement en définissant varchar (2 ^ n) ou même varchar (MAX).

Cela dit, vous devez toujours anticiper les implications potentielles sur le stockage et les performances lors de la définition d'une limite varchar () élevée. Par exemple, supposons que vous créez une colonne varchar (MAX) pour contenir les descriptions de produits avec une indexation de texte intégral. Si 99% des descriptions ne comptent que 500 caractères, et que vous obtenez soudainement quelqu'un qui remplace lesdites descriptions par des articles wikipedia, vous remarquerez peut-être des résultats importants imprévus en termes de stockage et de performances.

Une autre chose à considérer de Bill Karwin :

Il y a un impact possible sur les performances: dans MySQL, les tables temporaires et les tables MEMORY stockent une colonne VARCHAR en tant que colonne de longueur fixe, complétée à sa longueur maximale. Si vous concevez des colonnes VARCHAR beaucoup plus grandes que la plus grande taille dont vous avez besoin, vous consommerez plus de mémoire que nécessaire. Cela affecte l'efficacité du cache, la vitesse de tri, etc.

Fondamentalement, venez avec des contraintes commerciales raisonnables et des erreurs sur une taille légèrement plus grande. Comme l'a souligné @onedaywhen, les noms de famille au Royaume-Uni comptent généralement entre 1 et 35 caractères. Si vous décidez de le faire varchar (64), vous n'allez vraiment rien faire de mal ... à moins que vous ne stockiez le nom de famille de ce type qui contiendrait jusqu'à 666 caractères. Dans ce cas, peut-être que varchar (1028) a plus de sens.

Et au cas où cela serait utile, voici à quoi pourraient ressembler varchar 2 ^ 5 à 2 ^ 10 s'il est rempli:

varchar(32)     Lorem ipsum dolor sit amet amet.

varchar(64)     Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donecie

varchar(128)    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donecie
                vestibulum massa. Nullam dignissim elementum molestie. Vehiculas

varchar(256)    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donecie
                vestibulum massa. Nullam dignissim elementum molestie. Vehiculas
                velit metus, sit amet tristique purus condimentum eleifend. Quis
                que mollis magna vel massa malesuada bibendum. Proinde tincidunt

varchar(512)    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donecie
                vestibulum massa. Nullam dignissim elementum molestie. Vehiculas
                velit metus, sit amet tristique purus condimentum eleifend. Quis
                que mollis magna vel massa malesuada bibendum. Proinde tincidunt
                dolor tellus, sit amet porta neque varius vitae. Seduse molestie
                lacus id lacinia tempus. Vestibulum accumsan facilisis lorem, et
                mollis diam pretium gravida. In facilisis vitae tortor id vulput
                ate. Proin ornare arcu in sollicitudin pharetra. Crasti molestie

varchar(1024)   Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donecie
                vestibulum massa. Nullam dignissim elementum molestie. Vehiculas
                velit metus, sit amet tristique purus condimentum eleifend. Quis
                que mollis magna vel massa malesuada bibendum. Proinde tincidunt
                dolor tellus, sit amet porta neque varius vitae. Seduse molestie
                lacus id lacinia tempus. Vestibulum accumsan facilisis lorem, et
                mollis diam pretium gravida. In facilisis vitae tortor id vulput
                ate. Proin ornare arcu in sollicitudin pharetra. Crasti molestie
                dapibus leo lobortis eleifend. Vivamus vitae diam turpis. Vivamu
                nec tristique magna, vel tincidunt diam. Maecenas elementum semi
                quam. In ut est porttitor, sagittis nulla id, fermentum turpist.
                Curabitur pretium nibh a imperdiet cursus. Sed at vulputate este
                proin fermentum pretium justo, ac malesuada eros et Pellentesque
                vulputate hendrerit molestie. Aenean imperdiet a enim at finibus
                fusce ut ullamcorper risus, a cursus massa. Nunc non dapibus vel
                Lorem ipsum dolor sit amet, consectetur Praesent ut ultrices sit
Trousse
la source
31

La meilleure valeur est celle qui convient aux données telles que définies dans le domaine sous-jacent.

Pour certains domaines, VARCHAR(10)convient à l' Nameattribut, car d'autres domaines VARCHAR(255)peuvent être le meilleur choix.

Oded
la source
15

En ajoutant à la réponse de a_horse_with_no_name vous pourriez trouver ce qui suit d'intérêt ...

cela ne fait aucune différence que vous déclariez une colonne comme VARCHAR (100) ou VACHAR (500).

-- try to create a table with max varchar length
drop table if exists foo;
create table foo(name varchar(65535) not null)engine=innodb;

MySQL Database Error: Row size too large.

-- try to create a table with max varchar length - 2 bytes for the length
drop table if exists foo;
create table foo(name varchar(65533) not null)engine=innodb;

Executed Successfully

-- try to create a table with max varchar length with nullable field
drop table if exists foo;
create table foo(name varchar(65533))engine=innodb;

MySQL Database Error: Row size too large.

-- try to create a table with max varchar length with nullable field
drop table if exists foo;
create table foo(name varchar(65532))engine=innodb;

Executed Successfully

N'oubliez pas le ou les octets de longueur et l'octet nullable:

name varchar(100) not null sera de 1 octet (longueur) + jusqu'à 100 caractères (latin1)

name varchar(500) not null sera de 2 octets (longueur) + jusqu'à 500 caractères (latin1)

name varchar(65533) not null sera de 2 octets (longueur) + jusqu'à 65533 caractères (latin1)

name varchar(65532) sera de 2 octets (longueur) + jusqu'à 65 532 caractères (latin1) + 1 octet nul

J'espère que cela t'aides :)

Jon Black
la source
Vous utilisez MySQL, et la question concerne MSSQL
Bogdan Mart
6

Vérifiez toujours auprès de votre expert en domaine d'activité. Si c'est vous, recherchez une norme de l'industrie. Si, par exemple, le domaine en question est le nom de famille (nom de famille) d'une personne physique, pour une entreprise au Royaume - Uni, j'irais dans le catalogue des normes de données UK Govtalk pour obtenir des informations sur la personne et découvrir qu'un nom de famille comprendra entre 1 et 35 caractères. .

un jour
la source
3

Je n'ai pas vérifié cela récemment, mais je sais par le passé avec Oracle que le pilote JDBC réservait une partie de la mémoire lors de l'exécution de la requête pour conserver le jeu de résultats. La taille du bloc de mémoire dépend des définitions de colonne et de la taille d'extraction. La longueur des colonnes varchar2 affecte donc la quantité de mémoire réservée. Cela m'a causé de sérieux problèmes de performances il y a des années, car nous utilisions toujours varchar2 (4000) (le maximum à l'époque) et la collecte des ordures était beaucoup moins efficace qu'aujourd'hui.

user1041892
la source
-2

Dans un sens, vous avez raison, même si tout ce qui est inférieur à 2 ^ 8 caractères sera enregistré comme octet de données.

Si vous tenez compte du caractère de base qui laisse quoi que ce soit avec un VARCHAR <255 comme consommant la même quantité d'espace.

255 est une bonne définition de base, sauf si vous souhaitez particulièrement réduire les entrées excessives.

Dale Willis
la source
" même si tout ce qui est inférieur à 2 ^ 8 caractères sera toujours enregistré comme octet de données " - faux. La base de données stocke uniquement autant de caractères que ceux fournis dans un type VARCHAR. Aucun espace n'est "enregistré", réservé ou initialisé lors de la déclaration d' une colonne.
a_horse_with_no_name