web-dev-qa-db-fra.com

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

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

Gardez également à l'esprit qu'il existe souvent une très grande différence entre un CHAR et un VARCHAR lors de la comparaison d'index

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

J'ai trouvé des pages sur Oracle affirmant que CHAR est plus ou moins un alias pour VARCHAR et donc les performances d'index sont les mêmes, mais je n'ai rien trouvé de définitif sur Postgres.

16
LetMeSOThat4U

CHAR et VARCHAR sont 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 y a une différence qui peut faire une différence dans les performances: une colonne char est toujours complétée à la longueur définie. Donc, si vous définissez une colonne comme char(100) et une comme varchar(100) mais ne stockez que 10 caractères dans chacune, la colonne char(100) utilise 100 caractères pour chaque valeur (le 10 caractères que vous avez stockés, plus 90 espaces), tandis que la colonne varchar ne contient que 10 caractères.

La comparaison de 100 caractères avec 100 caractères va être plus lente que la comparaison de 10 caractères avec 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 stockez toujours exactement 10 caractères, alors il n'y a absolument aucune différence (c'est vrai pour Oracle et Postgres)

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


Gardez également à l'esprit qu'il existe souvent une très grande différence entre un CHAR et un VARCHAR lors de la comparaison d'index

La citation ci-dessus est niquement true si (et seulement si) la colonne char est définie trop large (c'est-à-dire que vous perdez de l'espace en raison du remplissage). Si la longueur de la colonne char 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 type de données char n'a pas vraiment d'utilisation réelle de Word. Utilisez simplement varchar (ou text dans Postgres) et oubliez que char existe.

24

Je suis d'accord avec tout dit par 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 le disent [~ # ~] doit [~ # ~] avoir des x-caractères. Bien que je sache que char() ne se plaint que si l'entrée dépasse la limite, je me protégerai fréquemment contre les sous-exécutions dans une contrainte CHECK. 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 de presque utilisez toujours text . Vous posez également des questions sur varchar(n). Je n'utilise jamais cela . 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 text 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 également varchar(n). Cependant, je ne vois rien qui corresponde à ces critères.

Notes complémentaires

Questions et réponses connexes:

6
Evan Carroll

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.

1
user939857