Performances de l'indice pour CHAR vs VARCHAR (Postgres)


16

Dans cette réponse ( /programming/517579/strings-as-primary-keys-in-sql-database ) une seule remarque a attiré mon attention:

Gardez également à l'esprit qu'il y a souvent une très grande différence entre un CHAR et un VARCHAR lors des comparaisons d'index

Est-ce que cela s'applique / s'applique toujours à Postgres?

J'ai trouvé des pages sur Oracle affirmant qu'il CHARs'agit plus ou moins d'un alias VARCHARet donc les performances de l'index sont les mêmes, mais je n'ai rien trouvé de définitif sur Postgres.

Réponses:


24

CHARet VARCHARsont implémentés exactement de la même manière dans Postgres (et Oracle). Il n'y a aucune différence de vitesse lors de l'utilisation de ces types de données.

Cependant, il existe une différence qui peut faire une différence dans les performances: une charcolonne est toujours complétée à la longueur définie. Donc, si vous définissez une colonne en tant que char(100)et une en tant que varchar(100)mais ne stockez que 10 caractères dans chacune, la char(100)colonne utilise 100 caractères pour chaque valeur (les 10 caractères que vous avez stockés, plus 90 espaces), tandis que la varcharcolonne ne stocke que 10 caractères.

Comparer 100 caractères à 100 caractères va être plus lent que comparer 10 caractères à 10 caractères - bien que je doute que vous puissiez réellement mesurer cette différence dans une requête SQL.

Si vous déclarez les deux avec une longueur de 10 caractères et que vous y stockez toujours exactement 10 caractères, il n'y a absolument aucune différence (cela est vrai pour Oracle et Postgres)

La seule différence est donc le remplissage effectué pour le chartype de données.


Gardez également à l'esprit qu'il y a souvent une très grande différence entre un CHAR et un VARCHAR lors des comparaisons d'index

La citation ci - dessus est uniquement vrai si (et seulement si) la charcolonne est définie trop large (vous perdez l' espace en raison de rembourrage). Si la longueur de la charcolonne est toujours utilisée complètement (donc aucun remplissage ne se produit), alors la citation ci-dessus est fausse (au moins pour Postgres et Oracle)


De mon point de vue, le chartype de données n'a pas vraiment d'utilisation réelle. Utilisez simplement varchar(ou textdans Postgres) et oubliez que cela charexiste.


2
Comparer 100 caractères à 100 caractères va être plus lent que comparer 10 caractères à 10 caractères - bien que je doute que vous puissiez réellement mesurer cette différence dans une requête SQL. - En fonction de ce que fait la requête en plus du tri, la différence peut être énorme. C'est pourquoi Postgres 9.5 a une nouvelle fonctionnalité de «touches abrégées»: pgeoghegan.blogspot.de/2015/01/…
chirlu

6

Je suis d'accord avec tout ce que dit a_horse_with_no_name, et je suis généralement d'accord avec les commentaires d'Erwin:

Non, l'omble est inférieur (et obsolète). text et varchar font (presque) la même chose.

Métadonnées

À une exception près, la seule fois que j'utilise, char()c'est quand je veux que les métadonnées disent que cela DOIT avoir des caractères x. Bien que je sache que cela char()ne se plaint que si l'entrée dépasse la limite, je vais souvent me protéger contre les sous-exécutions dans une CHECKcontrainte. Par exemple,

CREATE TABLE foo (
  x char(10) CHECK ( length(x) = 10 )
);
INSERT INTO foo VALUES (repeat('x', 9));

Je le fais pour plusieurs raisons,

  1. char(x)est parfois déduit avec les chargeurs de schéma comme étant une colonne de largeur fixe. Cela peut faire la différence dans un langage optimisé pour les chaînes de largeur fixe.
  2. Il établit une convention qui a du sens et est facilement appliquée. Je peux écrire un chargeur de schéma dans un langage pour générer du code à partir de cette convention.

Besoin d'un exemple de l'endroit où je peux le faire,

  1. Abréviations d'état à deux lettres, mais comme cette liste peut être énumérée, je le fais généralement avec un ENUM.
  2. Numéros d'identification du véhicule
  3. Numéros de modèle (de taille fixe)

Sur les erreurs

Notez que certaines personnes peuvent être mal à l'aise avec l'incongruité des messages d'erreur des deux côtés de la limite, mais cela ne me dérange pas

test=# INSERT INTO foo VALUES (repeat('x', 9));
ERROR:  new row for relation "foo" violates check constraint "foo_x_check"
DETAIL:  Failing row contains (xxxxxxxxx ).
test=# INSERT INTO foo VALUES (repeat('x', 11));
ERROR:  value too long for type character(10)

Contraste avec varchar

De plus, je pense que la suggestion ci-dessus correspond très bien à une convention d' utilisation presque toujourstext . Vous demandez varchar(n)aussi. Je n'utilise jamais ça . Au moins, je ne me souviens pas de la dernière fois que j'ai utilisé varchar(n).

  • Si une spécification a un champ de largeur statique auquel je fais confiance, j'utilise char(n),
  • Sinon, j'utilise textce qui est effectivement varchar(pas de limite)

Si je trouvais une spécification qui avait des touches de texte de longueur variable qui étaient significatives et que je faisais confiance pour avoir une longueur maximale constante, j'utiliserais varchar(n)aussi. Cependant, je ne vois rien qui corresponde à ces critères.

Notes complémentaires

Questions et réponses connexes:


1

Postgresql

sales_reporting_db=# create table x (y char(2));
CREATE TABLE
sales_reporting_db=# insert into x values ('Y');
INSERT 0 1
sales_reporting_db=# select '*' || y || '*' from x;
 ?column? 
----------
 *Y*

Oracle

SQL> create table x ( y char(2));

Table created.

SQL> insert into x values ('Y');

1 row created.

SQL> select '*' || y || '*' from x;

'*'|
----
*Y *

Postgresql n'a pas rempli d'espaces.


Ce n'est qu'une illusion d'optique dans Postgres. EssayezSELECT pg_column_size(y) FROM x;
dezso

-2

J'ai trouvé cela très utile et une explication rapide en 3 lignes:

De CHAR (n) Vs VARCHAR (N) Vs Text In Postgres

  • Si vous souhaitez stocker du texte de longueur inconnue, utilisez le TEXTtype de données.
  • Si vous souhaitez stocker du texte avec une longueur inconnue, mais que vous connaissez la longueur maximale, utilisez VARCHAR(n).
  • Si vous souhaitez stocker du texte dont la longueur exacte est connue, utilisez CHAR(N).
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.