Quels sont les cas d’utilisation de la sélection de CHAR plutôt que de VARCHAR en SQL ?

StackOverflow https://stackoverflow.com/questions/59667

  •  09-06-2019
  •  | 
  •  

Question

Je me rends compte que CHAR est recommandé si toutes mes valeurs sont à largeur fixe.Mais alors quoi?Pourquoi ne pas simplement choisir VARCHAR pour tous les champs de texte, juste pour être sûr.

Était-ce utile?

La solution

Choisissez généralement CARBONISER si toutes les lignes sont proches du même longueur.Prendre VARCHAR quand le la longueur varie significativement.CHAR peut aussi être un peu plus rapide car toutes les lignes ont la même longueur.

Cela varie selon l'implémentation de la base de données, mais généralement VARCHAR utilise un ou deux octets de stockage supplémentaires (pour la longueur ou la terminaison) en plus des données réelles.Donc (en supposant que vous utilisez un jeu de caractères d'un octet) en stockant le mot "FooBar"

  • CHAR(6) = 6 octets (pas de surcharge)
  • VARCHAR(10) = 8 octets (2 octets de surcharge)
  • CHAR(10) = 10 octets (4 octets de surcharge)

L’essentiel est CARBONISER peut être plus rapide et plus efficace en termes d'espace pour des données relativement de même longueur (dans une différence de longueur de deux caractères).

Note:Microsoft SQL a 2 octets de surcharge pour un VARCHAR.Cela peut varier d'un DB à l'autre, mais généralement il y a au moins 1 octet de surcharge nécessaire pour indiquer la longueur ou l'EOL sur un VARCHAR.

Comme Gaven l'a souligné dans les commentaires, si vous utilisez un jeu de caractères multi-octets de longueur variable comme UTF8, CHAR stocke le nombre maximum d'octets nécessaires pour stocker le nombre de caractères.Ainsi, si UTF8 a besoin d'au plus 3 octets pour stocker un caractère, alors CHAR(6) sera fixé à 18 octets, même s'il ne stocke que des caractères latin1.Donc, dans ce cas, VARCHAR devient un bien meilleur choix.

Autres conseils

Si vous travaillez avec moi et avec Oracle, je vous ferais probablement utiliser varchar dans presque toutes les circonstances.L'hypothèse selon laquelle char utilise moins de puissance de traitement que varchar c'est peut-être vrai... pour l'instant... mais les moteurs de bases de données s'améliorent avec le temps et ce genre de règle générale est en train de devenir un futur "mythe".

Autre chose:Je n'ai jamais vu de problème de performances parce que quelqu'un a décidé d'opter pour varchar.Vous utiliserez bien mieux votre temps en écrivant du bon code (moins d'appels à la base de données) et du SQL efficace (comment fonctionnent les index, comment l'optimiseur prend-il des décisions, pourquoi exists plus rapide que in généralement...).

Réflexion finale :J'ai vu toutes sortes de problèmes avec l'utilisation de CHAR, les personnes recherchant « » alors qu'elles devraient rechercher  », ou les personnes recherchant « FOO » alors qu'elles devraient rechercher « FOO (un tas d'espaces ici) », ou les personnes qui ne coupent pas les espaces de fin, ou les bugs avec Powerbuilder ajoutant jusqu'à 2 000 espaces à la valeur renvoyée par une procédure Oracle.

En plus des avantages en termes de performances, CHAR peut être utilisé pour indiquer que toutes les valeurs devrait avoir la même longueur, par exemple une colonne pour les États-Unisabréviations d'état.

Char est un peu plus rapide, donc si vous avez une colonne dont vous SAVEZ qu'elle aura une certaine longueur, utilisez char.Par exemple, stocker (M)ale/(F)emale/(U)nknown pour le sexe, ou 2 caractères pour un État américain.

NChar ou Char fonctionnent-ils mieux que leurs alternatives var ?

Excellente question.La réponse simple est oui dans certaines situations.Voyons si cela peut s'expliquer.

Évidemment, nous savons tous que si je crée une table avec une colonne de varchar(255) (appelons cette colonne maColonne) et que j'insère un million de lignes mais que je ne mets que quelques caractères dans maColonne pour chaque ligne, la table sera beaucoup plus petite (dans l'ensemble nombre de pages de données nécessaires au moteur de stockage) que si j'avais créé myColumn en tant que char(255).Chaque fois que je fais une opération (DML) sur cette table et demande beaucoup de lignes, ce sera plus rapide lorsque myColumn est varchar car je n'ai pas à le faire se déplacer autour de tous ces espaces "supplémentaires" à la fin.Déplacez-vous, comme lorsque SQL Server effectue des tris internes, par exemple lors d'une opération distincte ou d'union, ou s'il choisit une fusion lors de son plan de requête, etc.Le déplacement peut également signifier le temps nécessaire pour transférer les données du serveur vers mon ordinateur local ou vers un autre ordinateur ou partout où elles seront consommées.

Mais l’utilisation de varchar entraîne une certaine surcharge.SQL Server doit utiliser un indicateur de deux octets (surcharge) pour, sur chaque ligne, savoir combien d'octets contient myColumn de cette ligne particulière.Ce ne sont pas les 2 octets supplémentaires qui posent le problème, c'est le fait de devoir "décoder" la longueur des données dans myColumn sur chaque ligne.

D'après mon expérience, il est plus logique d'utiliser char au lieu de varchar sur les colonnes qui seront jointes dans les requêtes.Par exemple la clé primaire d'une table ou une autre colonne qui sera indexée.CustomerNumber sur une table démographique, ou CodeID sur une table de décodage, ou peut-être OrderNumber sur une table de commande.En utilisant char, le moteur de requête peut effectuer la jointure plus rapidement car il peut effectuer une arithmétique de pointeur directe (de manière déterministe) plutôt que d'avoir à déplacer ses pointeurs d'un nombre variable d'octets lors de la lecture des pages.Je sais que je t'ai peut-être perdu sur cette dernière phrase.Les jointures dans SQL Server sont basées sur l'idée de «prédicats». Un prédicat est une condition.Par exemple myColumn = 1 ou OrderNumber < 500.

Ainsi, si SQL Server exécute une instruction DML et que les prédicats ou les « clés » jointes ont une longueur fixe (caractère), le moteur de requête n'a pas à faire autant de travail pour faire correspondre les lignes d'une table aux lignes de un autre tableau.Il n'aura pas besoin de déterminer la durée des données dans la ligne, puis de parcourir la chaîne pour trouver la fin.Tout cela prend du temps.

Gardez à l’esprit que cela peut facilement être mal mis en œuvre.J'ai vu des caractères utilisés pour les champs de clé primaire dans les systèmes en ligne.La largeur doit rester petite, c'est-à-direchar(15) ou quelque chose de raisonnable.Et cela fonctionne mieux dans les systèmes en ligne car vous ne récupérez ou n'insérez généralement qu'un petit nombre de lignes, donc devoir "réduire" les espaces de fin que vous obtiendrez dans le jeu de résultats est une tâche triviale plutôt que de devoir rejoindre des millions de lignes. lignes d'une table à des millions de lignes sur une autre table.

Une autre raison pour laquelle CHAR a du sens par rapport à varchar sur les systèmes en ligne est qu'il réduit les fractionnements de pages.En utilisant char, vous "réservez" (et gaspillez) essentiellement cet espace, donc si un utilisateur arrive plus tard et met plus de données dans cette colonne, SQL lui a déjà alloué de l'espace et y va.

Une autre raison d’utiliser CHAR est similaire à la deuxième raison.Si un programmeur ou un utilisateur effectue une mise à jour « par lots » sur des millions de lignes, en ajoutant par exemple une phrase à un champ de note, vous ne recevrez pas d'appel de votre administrateur de base de données au milieu de la nuit pour vous demander pourquoi ses lecteurs sont pleins.En d’autres termes, cela conduit à une croissance plus prévisible de la taille d’une base de données.

Voilà donc 3 façons dont un système en ligne (OLTP) peut bénéficier de char plutôt que de varchar.Je n'utilise presque jamais char dans un scénario d'entrepôt/analyse/OLAP, car vous avez généralement TELLEMENT de données que toutes ces colonnes de caractères peuvent représenter une perte d'espace considérable.

Gardez à l'esprit que char peut rendre votre base de données beaucoup plus grande, mais la plupart des outils de sauvegarde ont une compression des données, de sorte que vos sauvegardes ont tendance à avoir à peu près la même taille que si vous aviez utilisé varchar.Par exemple LiteSpeed ​​ou RedGate SQL Backup.

Une autre utilisation concerne les vues créées pour exporter des données vers un fichier de largeur fixe.Disons que je dois exporter certaines données vers un fichier plat pour être lu par un ordinateur central.Sa largeur est fixe (non délimitée).J'aime stocker les données dans ma table "stade" en tant que varchar (consommant ainsi moins d'espace sur ma base de données), puis utiliser une vue pour CAST tout en son équivalent char, avec la longueur correspondant à la largeur de la largeur fixe pour cette colonne .Par exemple:

create table tblStagingTable (
pkID BIGINT (IDENTITY,1,1),
CustomerFirstName varchar(30),
CustomerLastName varchar(30),
CustomerCityStateZip varchar(100),
CustomerCurrentBalance money )

insert into tblStagingTable
(CustomerFirstName,CustomerLastName, CustomerCityStateZip) ('Joe','Blow','123 Main St Washington, MD 12345', 123.45)

create view vwStagingTable AS
SELECT CustomerFirstName = CAST(CustomerFirstName as CHAR(30)),
CustomerLastName = CAST(CustomerLastName as CHAR(30)),
CustomerCityStateZip = CAST(CustomerCityStateZip as CHAR(100)),
CustomerCurrentBalance = CAST(CAST(CustomerCurrentBalance as NUMERIC(9,2)) AS CHAR(10))

SELECT * from vwStagingTable

C'est cool car en interne mes données prennent moins de place car elles utilisent varchar.Mais lorsque j'utilise DTS ou SSIS ou même simplement un copier-coller de SSMS vers le Bloc-notes, je peux utiliser la vue et obtenir le bon nombre d'espaces de fin.Dans DTS, nous avions une fonctionnalité appelée, bon sang, j'oublie, je pense qu'elle s'appelait « suggérer des colonnes » ou quelque chose du genre.Dans SSIS, vous ne pouvez plus faire cela, vous devez définir fastidieusement le gestionnaire de connexions de fichiers plats.Mais puisque vous avez configuré votre vue, SSIS peut connaître la largeur de chaque colonne et peut vous faire gagner beaucoup de temps lors de la création de vos tâches de flux de données.

Donc en fin de compte...utilisez Varchar.Il existe un très petit nombre de raisons d'utiliser char et c'est uniquement pour des raisons de performances.Si vous avez un système avec des centaines de millions de lignes, vous verrez une différence notable si les prédicats sont déterministes (char), mais pour la plupart des systèmes utilisant char, cela gaspille simplement de l'espace.

J'espère que cela pourra aider.Jeff

Il existe des avantages en termes de performances, mais en voici un qui n'a pas été mentionné :migration de lignes.Avec char, vous réservez tout l'espace à l'avance. Disons donc que vous avez un char (1000) et que vous stockez 10 caractères, vous utiliserez les 1000 caractères d'espace.Dans un varchar2(1000), vous n'utiliserez que 10 caractères.Le problème survient lorsque vous modifiez les données.Supposons que vous mettiez à jour la colonne pour qu'elle contienne désormais 900 caractères.Il est possible que l'espace pour développer le varchar ne soit pas disponible dans le bloc actuel.Dans ce cas, le moteur de base de données doit migrer la ligne vers un autre bloc et créer un pointeur dans le bloc d'origine vers la nouvelle ligne du nouveau bloc.Pour lire ces données, le moteur DB devra désormais lire 2 blocs.
Personne ne peut dire avec équivoque que varchar ou char sont meilleurs.Il y a un espace pour un compromis temporel et pour déterminer si les données seront mises à jour, surtout s'il y a de bonnes chances qu'elles augmentent.

Il existe une différence entre une optimisation précoce des performances et l’utilisation d’une règle de type meilleure pratique.Si vous créez de nouvelles tables dans lesquelles vous aurez toujours un champ de longueur fixe, il est logique d'utiliser CHAR, vous devriez l'utiliser dans ce cas.Il ne s'agit pas d'une optimisation précoce, mais plutôt de la mise en œuvre d'une règle empirique (ou de bonnes pratiques).

c'est à dire.- Si vous avez un champ d'état de 2 lettres, utilisez CHAR(2).Si vous disposez d'un champ avec les noms d'état réels, utilisez VARCHAR.

Je choisirais varchar à moins que la colonne ne stocke une valeur fixe comme le code de l'État américain - qui comporte toujours 2 caractères et que la liste des codes d'État américains valides ne change pas souvent :).

Dans tous les autres cas, même pour stocker un mot de passe haché (de longueur fixe), je choisirais varchar.

Pourquoi -- la colonne de type char est toujours remplie d'espaces, ce qui en fait une colonne ma_colonne défini comme char(5) avec la valeur 'ABC' dans la comparaison :

my_column = 'ABC' -- my_column stores 'ABC  ' value which is different then 'ABC'

FAUX.

Ce fonctionnalité pourrait entraîner de nombreux bugs irritants pendant le développement et rendre les tests plus difficiles.

CHAR occupe moins d'espace de stockage que VARCHAR si toutes vos valeurs de données dans ce champ ont la même longueur.Maintenant, peut-être qu'en 2009, une base de données de 800 Go est à toutes fins utiles la même qu'une base de données de 810 Go si vous convertissez les VARCHAR en CHAR, mais pour les chaînes courtes (1 ou 2 caractères), CHAR est toujours une "meilleure pratique" de l'industrie, je dirais.

Maintenant, si vous regardez la grande variété de types de données que la plupart des bases de données proposent, même pour les entiers uniquement (bit, tiny, int, bigint), il y a des raisons de choisir l'un plutôt que l'autre.Choisir simplement bigint à chaque fois, c'est en fait ignorer un peu les objectifs et les utilisations du champ.Si un champ représente simplement l'âge d'une personne en années, un bigint est excessif.Ce n’est pas nécessairement « faux », mais ce n’est pas efficace.

Mais c'est un argument intéressant, et à mesure que les bases de données s'améliorent avec le temps, on pourrait affirmer que CHAR vs VARCHAR devient moins pertinent.

Je maintiens le commentaire de Jim McKeeth.

De plus, l'indexation et les analyses complètes des tables sont plus rapides si votre table ne contient que des colonnes CHAR.Fondamentalement, l'optimiseur sera capable de prédire la taille de chaque enregistrement s'il ne contient que des colonnes CHAR, alors qu'il devra vérifier la valeur de taille de chaque colonne VARCHAR.

De plus, si vous mettez à jour une colonne VARCHAR vers une taille supérieure à son contenu précédent, vous pouvez forcer la base de données à reconstruire ses index (car vous avez forcé la base de données à déplacer physiquement l'enregistrement sur le disque).Alors qu'avec les colonnes CHAR, cela n'arrivera jamais.

Mais vous ne vous soucierez probablement pas des performances, à moins que votre table ne soit énorme.

Rappelez-vous les sages paroles de Djikstra.L’optimisation précoce des performances est la racine de tous les maux.

De nombreuses personnes ont souligné que si vous connaissez la longueur exacte de la valeur, l'utilisation de CHAR présente certains avantages.Mais même si le stockage des États américains sous CHAR(2) est une bonne chose aujourd'hui, lorsque vous recevez le message des ventes indiquant « Nous venons de réaliser notre première vente en Australie », vous êtes dans un monde de douleur.J'envoie toujours surestimer la durée que je pense que les champs devront durer plutôt que de faire une estimation « exacte » pour couvrir les événements futurs.VARCHAR m'apportera plus de flexibilité dans ce domaine.

Il y a une petite surcharge de traitement dans le calcul de la taille réelle nécessaire pour une valeur de colonne et l'allocation de l'espace pour un Varchar, donc si vous êtes sûr de la durée de la valeur, il est préférable d'utiliser Char et d'éviter le coup.

C’est le compromis classique entre espace et performances.

Dans MS SQL 2005, Varchar (ou NVarchar pour les langues nécessitant deux octets par caractère, c'est-à-dire le chinois) sont de longueur variable.Si vous effectuez un ajout à la ligne après son écriture sur le disque dur, les données seront localisées dans un emplacement non contigu à la ligne d'origine et entraîneront une fragmentation de vos fichiers de données.Cela affectera les performances.

Ainsi, si l'espace n'est pas un problème, les Char sont meilleurs en termes de performances, mais si vous souhaitez réduire la taille de la base de données, les varchars sont meilleurs.

Je pense que dans votre cas, il n'y a probablement aucune raison de ne pas choisir Varchar.Cela vous donne de la flexibilité et, comme l'ont mentionné un certain nombre de personnes interrogées, les performances sont désormais telles que, sauf dans des circonstances très spécifiques, nous, simples mortels (contrairement aux administrateurs de base de données de Google), ne remarquerons pas la différence.

Une chose intéressante à noter en ce qui concerne les types de base de données est que sqlite (une mini base de données populaire avec des performances assez impressionnantes) place tout dans la base de données sous forme de chaîne et tape à la volée.

J'utilise toujours VarChar et je le rends généralement beaucoup plus gros que ce dont j'aurais strictement besoin.Par exemple.50 pour Prénom, comme tu dis pourquoi ne pas juste par sécurité.

Fragmentation.Char réserve de l'espace et VarChar ne le fait pas.Un fractionnement de page peut être nécessaire pour permettre la mise à jour de varchar.

Je n'utiliserais JAMAIS de caractères.J'ai eu ce débat avec beaucoup de gens et ils évoquent toujours le cliché éculé selon lequel le char est plus rapide.Eh bien, je dis, combien plus vite ?De quoi parle-t-on ici, de millisecondes, de secondes et si oui de combien ?Vous me dites que parce que quelqu'un prétend que c'est quelques millisecondes plus rapide, nous devrions introduire des tonnes de bugs difficiles à corriger dans le système ?

Voici donc quelques problèmes que vous rencontrerez :

Chaque champ sera rempli, vous vous retrouverez donc pour toujours avec du code qui contient des RTRIMS partout.Cela représente également un énorme gaspillage d'espace disque pour les champs plus longs.

Disons maintenant que vous avez l'exemple par excellence d'un champ char d'un seul caractère mais que le champ est facultatif.Si quelqu'un transmet une chaîne vide à ce champ, cela devient un espace.Ainsi, lorsqu'une autre application/processus l'interroge, ils obtiennent un seul espace, s'ils n'utilisent pas rtrim.Nous avons eu des documents XML, des fichiers et d'autres programmes, qui affichent un seul espace, dans des champs facultatifs et qui cassent les choses.

Alors maintenant, vous devez vous assurer que vous transmettez des valeurs nulles et non une chaîne vide au champ char.Mais ce n’est PAS l’utilisation correcte de null.Voici l'utilisation de null.Disons que vous recevez un fichier d'un fournisseur

Nom|Sexe|Ville

Bob||Los Angeles

Si le sexe n'est pas spécifié, entrez Bob, une chaîne vide et Los Angeles dans le tableau.Disons maintenant que vous obtenez le fichier et que son format change et que le sexe n'est plus inclus mais l'était dans le passé.

Nom|Ville

Bob|Seattle

Eh bien, puisque le sexe n'est pas inclus, j'utiliserais null.Varchars prend en charge cela sans problème.

Char, en revanche, est différent.Vous devez toujours envoyer null.Si jamais vous envoyez une chaîne vide, vous vous retrouverez avec un champ contenant des espaces.

Je pourrais continuer encore et encore avec tous les bugs que j'ai dû corriger à partir des caractères et en environ 20 ans de développement.

Lorsque vous utilisez VARCHAR VALEURS SQL Server a besoin de 2 octets supplémentaires par ligne pour stocker des informations sur cette colonne alors que si vous utilisez du char, il n'en a pas besoin, à moins que vous ne vous soyez

Dans certaines bases de données SQL, VARCHAR sera complété jusqu'à sa taille maximale afin d'optimiser les décalages, afin d'accélérer les analyses et index complets des tables.

Pour cette raison, vous ne réalisez aucune économie d'espace en utilisant un VARCHAR(200) par rapport à un CHAR(200)

L'utilisation de CHAR (NCHAR) et de VARCHAR (NVARCHAR) entraîne des différences dans la manière dont le serveur de base de données stocke les données.Le premier introduit les espaces de fin ;J'ai rencontré un problème lors de son utilisation avec l'opérateur LIKE dans les fonctions SQL SERVER.Je dois donc le sécuriser en utilisant VARCHAR (NVARCHAR) à tout moment.

Par exemple, si nous avons une table TEST(ID INT, Statut CHAR(1)), et vous écrivez une fonction pour lister tous les enregistrements avec une valeur spécifique comme la suivante :

CREATE FUNCTION List(@Status AS CHAR(1) = '')
RETURNS TABLE
AS
RETURN
SELECT * FROM TEST
WHERE Status LIKE '%' + @Status '%'

Dans cette fonction, nous nous attendons à ce que lorsque nous mettons le paramètre par défaut, la fonction renvoie toutes les lignes, mais en fait ce n'est pas le cas.Changer le type de données @Status en VARCHAR résoudra le problème.

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