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.
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.
Réponses:
Choisissez généralement CHAR si toutes les lignes auront presque la même longueur . Choisissez VARCHAR lorsque la longueur varie considérablement. CHAR peut également être un peu plus rapide car toutes les lignes sont de 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) stocker le mot "FooBar"
En bout de ligne, CHAR peut être plus rapide et plus efficace en termes d'espace pour des données de même longueur (dans une différence de longueur de deux caractères).
Remarque : Microsoft SQL a 2 octets de surcharge pour un VARCHAR. Cela peut varier d'une base de données à l'autre, mais généralement il y a au moins 1 octet de surcharge nécessaire pour indiquer la longueur ou la fin de vie sur un VARCHAR.
Comme l'a souligné Gaven dans les commentaires, si vous utilisez un jeu de caractères multi-octets de longueur variable comme UTF8, CHAR stocke le nombre maximal d'octets nécessaires pour stocker le nombre de caractères. Donc, 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. Dans ce cas, VARCHAR devient donc un bien meilleur choix.
Si vous travaillez avec moi et que vous travaillez avec Oracle, je vous ferais probablement utiliser varchar
dans presque toutes les circonstances. L'hypothèse qui char
utilise moins de puissance de traitement que varchar
peut être vrai ... pour l'instant ... mais les moteurs de base de données s'améliorent avec le temps et ce genre de règle générale a fait un futur "mythe".
Autre chose: je n'ai jamais vu de problème de performance car quelqu'un a décidé d'y aller varchar
. Vous utiliserez beaucoup mieux votre temps à écrire 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 est-il exists
plus rapide que d' in
habitude ...).
Pensée finale: j'ai vu toutes sortes de problèmes avec l'utilisation de CHAR
, les gens qui recherchent `` quand ils devraient chercher '', ou les gens qui recherchent 'FOO' quand ils devraient chercher 'FOO (tas d'espaces ici)' ' , ou des personnes ne supprimant pas les blancs de fin, ou des bogues avec Powerbuilder ajoutant jusqu'à 2000 blancs à la valeur renvoyée par une procédure Oracle.
En plus des avantages de performance, CHAR
peut être utilisé pour indiquer que toutes les valeurs doivent être de la même longueur, par exemple, une colonne pour les abréviations des États américains.
CHAR
, vous devrez vous assurer que votre contrainte réduit le remplissage.
Char est un peu plus rapide, donc si vous avez une colonne que vous SAVEZ avoir 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?
Grande question. La réponse simple est oui dans certaines situations. Voyons si cela peut être expliqué.
É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 mets seulement 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 à me déplacer à la fin de tous ces espaces "supplémentaires". Déplacer, comme lorsque SQL Server effectue des tris internes, comme lors d'une opération distincte ou d'union, ou s'il choisit une fusion pendant son plan de requête, etc.
Mais il y a des frais généraux à utiliser varchar. SQL Server doit utiliser un indicateur de deux octets (surcharge) pour, sur chaque ligne, savoir combien d'octets cette colonne particulière contient ma colonne. Ce n'est pas les 2 octets supplémentaires qui posent le problème, c'est le fait de "décoder" la longueur des données dans myColumn sur chaque ligne.
D'après mes expériences, il est plus judicieux 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 plus rapidement la jointure car il peut effectuer l'arithmétique du pointeur droit (de manière déterministe) plutôt que de déplacer ses pointeurs d'une quantité variable d'octets lors de la lecture des pages. Je sais que je pourrais vous avoir 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.
Donc, si SQL Server exécute une instruction DML et que les prédicats ou les "clés" joints sont de longueur fixe (char), le moteur de requête n'a pas à faire autant de travail pour faire correspondre les lignes d'une table aux lignes de une autre table. Il ne sera pas nécessaire de savoir combien de temps les données sont dans la ligne, puis de parcourir la chaîne pour trouver la fin. Tout cela prend du temps.
Gardez maintenant à 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 être réduite, c.-à-d. Char (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 avoir à "rtrim" ces espaces de fin que vous obtiendrez dans le jeu de résultats est une tâche triviale au lieu d'avoir à rejoindre des millions de des 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'elle réduit les divisions de page. En utilisant char, vous "réservez" (et gaspillez) 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 une phrase à un champ de note par exemple, vous ne recevrez pas d'appel de votre DBA au milieu de la nuit pour vous demander pourquoi leurs lecteurs sont pleins. En d'autres termes, cela conduit à une croissance plus prévisible de la taille d'une base de données.
Ce sont donc 3 façons dont un système en ligne (OLTP) peut bénéficier de char sur varchar. Je n'utilise presque jamais char dans un scénario d'entrepôt / d'analyse / OLAP car généralement vous avez tellement de données que toutes ces colonnes de char peuvent ajouter jusqu'à beaucoup d'espace gaspillé.
Gardez à l'esprit que char peut augmenter considérablement la taille de votre base de données, mais la plupart des outils de sauvegarde ont une compression de données, de sorte que vos sauvegardes ont généralement la même taille que si vous aviez utilisé varchar. Par exemple, LiteSpeed ou RedGate SQL Backup.
Une autre utilisation est dans les vues créées pour exporter des données vers un fichier à largeur fixe. Disons que je dois exporter certaines données dans un fichier plat pour être lues par un ordinateur central. C'est une largeur fixe (non délimitée). J'aime stocker les données dans ma table "intermédiaire" en tant que varchar (consommant ainsi moins d'espace sur ma base de données), puis utiliser une vue pour tout CAST à 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 juste 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 l'habitude d'avoir une fonctionnalité appelée, putain j'oublie que je pense qu'elle s'appelait "suggérer des colonnes" ou quelque chose. Dans SSIS, vous ne pouvez plus faire cela, vous devez définir fastidieusement le gestionnaire de connexion de fichiers plats. Mais comme vous avez configuré votre vue, SSIS peut connaître la largeur de chaque colonne et 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 y a un très petit nombre de raisons d'utiliser char et ce n'est que 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, l'utilisation de char 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é: la migration des lignes. Avec char, vous réservez tout l'espace à l'avance, alors disons que vous avez un char (1000), et que vous stockez 10 caractères, vous utiliserez les 1000 caractères de l'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 mettez à 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 maintenant lire 2 blocs.
Personne ne peut dire de manière équivoque que varchar ou char sont meilleurs. Il y a un espace pour le compromis temporel et la question de savoir si les données seront mises à jour, surtout s'il y a de fortes chances qu'elles augmentent.
Il existe une différence entre l'optimisation précoce des performances et l'utilisation d'un type de règle de meilleure pratique. Si vous créez de nouvelles tables où vous aurez toujours un champ de longueur fixe, il est logique d'utiliser CHAR, vous devriez l'utiliser dans ce cas. Ce n'est pas une optimisation précoce, mais plutôt l'implémentation d'une règle empirique (ou meilleure pratique).
ie - Si vous avez un champ d'état à 2 lettres, utilisez CHAR (2). Si vous avez un champ avec les noms d'état réels, utilisez VARCHAR.
Je choisirais varchar à moins que la colonne stocke une valeur fixe comme le code d'état américain - qui est toujours de 2 caractères et que la liste des codes d'états américains valides ne change pas souvent :).
Dans tous les autres cas, même si vous stockez un mot de passe haché (de longueur fixe), je choisirais varchar.
Pourquoi - la colonne de type char est toujours remplie d'espaces, ce qui fait que la colonne my_column est définie comme char (5) avec la valeur 'ABC' dans la comparaison:
my_column = 'ABC' -- my_column stores 'ABC ' value which is different then 'ABC'
faux.
Cette fonctionnalité peut entraîner de nombreux bugs irritants lors du développement et compliquer les tests.
CHAR prend moins d'espace de stockage que VARCHAR si toutes vos valeurs de données dans ce champ sont de la même longueur. Maintenant, peut-être qu'en 2009, une base de données de 800 Go est la même à toutes fins utiles qu'un 810 Go si vous avez converti 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 fournissent même pour les entiers seuls (bit, minuscule, int, bigint), il y a des raisons de choisir l'un plutôt que l'autre. Choisir simplement bigint à chaque fois est en fait un peu ignorant des buts et des utilisations du domaine. Si un champ représente simplement l'âge d'une personne en années, un bigint est exagéré. Maintenant, 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 faire valoir que CHAR vs VARCHAR devient moins pertinent.
Je maintiens le commentaire de Jim McKeeth.
De plus, l'indexation et les analyses de table complètes sont plus rapides si votre table ne contient que des colonnes CHAR. Fondamentalement, l'optimiseur sera en mesure de prédire la taille de chaque enregistrement s'il n'a que des colonnes CHAR, alors qu'il doit vérifier la valeur de la taille de chaque colonne VARCHAR.
De plus, si vous mettez à jour une colonne VARCHAR à 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). Avec les colonnes CHAR, cela n'arrivera jamais.
Mais vous ne vous soucierez probablement pas de la performance, à moins que votre table ne soit énorme.
Rappelez-vous les sages paroles de Djikstra. L'optimisation précoce des performances est à l'origine de tous les maux.
CHAR
colonne, les index doivent également être mis à jour. Il n'y a aucune différence dans la mise à jour d'une colonne VARCHAR ou CHAR à cet égard. Pensez à mettre FOO
à jour vers BAR
.
Beaucoup de gens ont souligné que si vous connaissez la longueur exacte de la valeur, l'utilisation de CHAR présente certains avantages. Mais tout en stockant les États américains sous le nom CHAR (2) est génial aujourd'hui, lorsque vous recevez le message des ventes que `` nous venons de faire notre première vente en Australie '', vous êtes dans un monde de douleur. J'envoie toujours pour surestimer combien de temps je pense que les champs devront être plutôt que de faire une supposition «exacte» pour couvrir les événements futurs. VARCHAR me donnera plus de flexibilité dans ce domaine.
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 cela a été mentionné par un certain nombre de répondants, les performances sont telles maintenant que, sauf dans des circonstances très spécifiques, nous, les mortels (contrairement à Google DBA), 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) met tout dans la base de données sous forme de chaîne et de types à la volée.
J'utilise toujours VarChar et le rend généralement beaucoup plus grand que ce dont j'ai besoin. Par exemple. 50 pour Firstname, comme vous dites pourquoi ne pas simplement être en sécurité.
Je n'utiliserais JAMAIS de caractères. J'ai eu ce débat avec beaucoup de gens et ils évoquent toujours le cliché fatigué que l'omble chevalier est plus rapide. Eh bien, je dis combien de temps plus rapide? De quoi parle-t-on ici, millisecondes, secondes et si oui combien? Vous me dites parce que quelqu'un prétend que ses quelques millisecondes sont plus rapides, nous devrions introduire des tonnes de bugs difficiles à corriger dans le système?
Voici donc quelques problèmes que vous rencontrerez:
Chaque champ sera rembourré, donc vous vous retrouvez avec du code pour toujours avec RTRIMS partout. C'est également un énorme gaspillage d'espace disque pour les champs plus longs.
Supposons maintenant que vous ayez l'exemple par excellence d'un champ char d'un seul caractère, mais le champ est facultatif. Si quelqu'un passe une chaîne vide à ce champ, cela devient un espace. Ainsi, lorsqu'un 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, affichons un seul espace, dans des champs optionnels et cassons les choses.
Alors maintenant, vous devez vous assurer que vous passez des valeurs nulles et non des chaînes vides, au champ char. Mais ce n'est PAS l'utilisation correcte de null. Voici l'utilisation de null. Disons que vous obtenez un fichier d'un fournisseur
Nom | Sexe | Ville
Bob || Los Angeles
Si le sexe n'est pas spécifié, saisissez Bob, chaîne vide et Los Angeles dans le tableau. Supposons maintenant que vous obteniez le fichier et que son format change et que le sexe ne soit plus inclus mais était dans le passé.
Nom | Ville
Bob | Seattle
Eh bien maintenant, puisque le sexe n'est pas inclus, j'utiliserais null. Les Varchars soutiennent cela sans problèmes.
Char en revanche est différent. Vous devez toujours envoyer null. Si vous envoyez une chaîne vide, vous vous retrouverez avec un champ contenant des espaces.
Je pourrais continuer indéfiniment avec tous les bugs que j'ai dû corriger à partir des caractères et en environ 20 ans de développement.
Le calcul de la taille réelle nécessaire pour une valeur de colonne et l'allocation de l'espace pour un Varchar nécessitent un léger surcoût de traitement.Par conséquent, si vous êtes sûr de la durée de la valeur, il est préférable d'utiliser Char et d'éviter le hit.
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 chinois) sont de longueur variable. Si vous ajoutez à la ligne après qu'elle a été écrite sur le disque dur, elle localisera les données dans un emplacement non contigieux à la ligne d'origine et conduira à la fragmentation de vos fichiers de données. Cela affectera les performances.
Donc, si l'espace n'est pas un problème, les caractères sont meilleurs pour les performances, mais si vous souhaitez réduire la taille de la base de données, les varchars sont meilleurs.
Fragmentation. Char réserve de l'espace et VarChar non. Le fractionnement de page peut être requis pour permettre la mise à jour de varchar.
CHAR
colonne.
Dans certaines bases de données SQL, VARCHAR sera complétée à sa taille maximale afin d'optimiser les décalages, ceci afin d'accélérer les analyses de table complètes et les index.
De ce fait, vous n'avez pas d'économie d'espace en utilisant un VARCHAR (200) par rapport à un CHAR (200)
L'utilisation de CHAR (NCHAR) et VARCHAR (NVARCHAR) apporte des différences dans la façon dont le serveur de base de données stocke les données. Le premier introduit des blancs 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 le temps.
Par exemple, si nous avons une table TEST (ID INT, Status CHAR (1)) et que vous écrivez une fonction pour répertorier 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.