PostgreSQL: différence entre le texte et varchar (variant les caractères)

620

Quelle est la différence entre le texttype de données et les types de données character varying( varchar)?

Selon la documentation

Si la variation de caractères est utilisée sans spécificateur de longueur, le type accepte des chaînes de n'importe quelle taille. Cette dernière est une extension PostgreSQL.

et

De plus, PostgreSQL fournit le type de texte, qui stocke des chaînes de n'importe quelle longueur. Bien que le texte de type ne soit pas dans la norme SQL, plusieurs autres systèmes de gestion de base de données SQL l'ont également.

Alors quelle est la différence?

Adam Matan
la source

Réponses:

746

Il n'y a pas de différence, sous le capot c'est tout varlena( tableau de longueur variable ).

Consultez cet article de Depesz: http://www.depesz.com/index.php/2010/03/02/charx-vs-varcharx-vs-varchar-vs-text/

Quelques points saillants:

Pour tout résumer:

  • char (n) - prend trop de place lorsqu'il s'agit de valeurs plus courtes que n(les remplit n) et peut conduire à des erreurs subtiles en raison de l'ajout d'espaces de fin, de plus il est problématique de changer la limite
  • varchar (n) - il est problématique de changer la limite dans l'environnement en direct (nécessite un verrouillage exclusif lors de la modification de la table)
  • varchar - tout comme le texte
  • texte - pour moi un gagnant - sur (n) types de données car il manque leurs problèmes, et sur varchar - parce qu'il a un nom distinct

L'article effectue des tests détaillés pour montrer que les performances des insertions et des sélections pour les 4 types de données sont similaires. Il examine également en détail d'autres moyens de limiter la longueur en cas de besoin. Les contraintes ou domaines basés sur la fonction offrent l'avantage d'une augmentation instantanée de la contrainte de longueur, et sur la base que la diminution d'une contrainte de longueur de chaîne est rare, depesz conclut que l'un d'entre eux est généralement le meilleur choix pour une limite de longueur.

Frank Heikens
la source
58
@axiopisty C'est un excellent article. Vous pourriez simplement dire: "Pourriez-vous tirer quelques extraits au cas où l'article tomberait?" J'ai essayé de résumer brièvement le contenu / les conclusions de l'article. J'espère que cela suffira à apaiser vos inquiétudes.
jpmc26
34
@axiopisty, à proprement parler, la réponse initiale disait " sous le capot, tout est varlena ", ce qui est certainement une information utile qui distingue cette réponse d'une réponse en lien uniquement.
Bruno
24
Une chose à garder à l'esprit avec une chaîne illimitée, c'est qu'ils ouvrent le potentiel d'abus. Si vous autorisez un utilisateur à avoir un nom de famille de n'importe quelle taille, vous pouvez avoir quelqu'un qui stocke de GRANDES quantités d'informations dans votre champ de nom de famille. Dans un article sur le développement de reddit, ils conseillent de "mettre une limite à tout".
Mark Hildreth
7
@MarkHildreth Bon point, bien que généralement des contraintes comme celle-ci soient appliquées plus loin dans une application ces jours-ci, afin que les règles (et les tentatives de violations / tentatives) puissent être gérées sans problème par l'interface utilisateur. Si quelqu'un veut toujours faire ce genre de chose dans la base de données, il peut utiliser des contraintes. Voir blog.jonanin.com/2013/11/20/postgresql-char-varchar qui comprend "un exemple d'utilisation de TEXT et de contraintes pour créer des champs avec plus de flexibilité que VARCHAR".
Ethan
4
@Ethan blog.jonanin.com/2013/11/20/postgresql-char-varchar -> Ceci est en panne, mais se trouve ici archive.is/6xhA5 .
MrR
115

En tant que « Types de caractères » dans les points de documentation sur, varchar(n), char(n)et textsont tous stockés de la même façon. La seule différence est que des cycles supplémentaires sont nécessaires pour vérifier la longueur, le cas échéant, et l'espace et le temps supplémentaires nécessaires si un rembourrage est nécessaire char(n).

Cependant, lorsque vous n'avez besoin de stocker qu'un seul caractère, l'utilisation du type spécial présente un léger avantage en termes de performances "char"(conservez les guillemets doubles - ils font partie du nom du type). Vous obtenez un accès plus rapide au champ et il n'y a pas de surcharge pour stocker la longueur.

Je viens de faire un tableau de 1 000 000 "char"choisis au hasard dans l'alphabet minuscule. Une requête pour obtenir une distribution de fréquence ( select count(*), field ... group by field) prend environ 650 millisecondes, contre environ 760 sur les mêmes données à l'aide d'un textchamp.

George
la source
18
techniquement, les guillemets ne font pas partie du nom du type. ils sont nécessaires pour le différencier du mot clé char.
Jasen
31
Techniquement, vous avez raison @Jasen ... Ce qui, bien sûr, est le meilleur type de correct
JohannesH
le type de données "char" n'est pas char?? Est-il valable de nos jours avec PostgreSQL 11+? ... Oui: "Le type "char"(notez les guillemets) est différent de char (1) en ce qu'il n'utilise qu'un seul octet de stockage. Il est utilisé en interne dans les catalogues système comme type d'énumération simpliste ." , guide / caractère de type de données .
Peter Krauss
64

MISE À JOUR DES RÉFÉRENCES POUR 2016 (pg9.5 +)

Et en utilisant des benchmarks "SQL pur" (sans aucun script externe)

  1. utiliser n'importe quel string_generator avec UTF8

  2. repères principaux:

    2.1. INSÉRER

    2.2. SELECT comparant et comptant


CREATE FUNCTION string_generator(int DEFAULT 20,int DEFAULT 10) RETURNS text AS $f$
  SELECT array_to_string( array_agg(
    substring(md5(random()::text),1,$1)||chr( 9824 + (random()*10)::int )
  ), ' ' ) as s
  FROM generate_series(1, $2) i(x);
$f$ LANGUAGE SQL IMMUTABLE;

Préparer un test spécifique (exemples)

DROP TABLE IF EXISTS test;
-- CREATE TABLE test ( f varchar(500));
-- CREATE TABLE test ( f text); 
CREATE TABLE test ( f text  CHECK(char_length(f)<=500) );

Effectuez un test de base:

INSERT INTO test  
   SELECT string_generator(20+(random()*(i%11))::int)
   FROM generate_series(1, 99000) t(i);

Et d'autres tests,

CREATE INDEX q on test (f);

SELECT count(*) FROM (
  SELECT substring(f,1,1) || f FROM test WHERE f<'a0' ORDER BY 1 LIMIT 80000
) t;

... Et utilisez EXPLAIN ANALYZE.

À JOUR 2018 (p. 10)

petite modification pour ajouter les résultats de 2018 et renforcer les recommandations.


Résultats en 2016 et 2018

Mes résultats, après moyenne, sur de nombreuses machines et de nombreux tests: tout de même
(écart type statistiquement inférieur).

Recommandation

  • Utilisez le texttype de données,
    évitez l'ancien varchar(x)car parfois ce n'est pas un standard, par exemple dans les CREATE FUNCTIONclauses varchar(x)varchar(y) .

  • exprimer les limites (avec les mêmes varcharperformances!) par la CHECKclause with dans le CREATE TABLE
    eg CHECK(char_length(x)<=10).
    Avec une perte de performances négligeable dans INSERT / UPDATE, vous pouvez également contrôler les plages et la structure des chaînes,
    par exempleCHECK(char_length(x)>5 AND char_length(x)<=20 AND x LIKE 'Hello%')

Peter Krauss
la source
Donc, cela n'a pas d'importance que j'ai fait toutes mes colonnes varchar au lieu de texte? Je n'ai pas précisé la longueur même si certains ne sont que 4 à 5 caractères et certainement pas 255.
trench
1
@trench oui, cela n'a pas d'importance
FuriousFolder
1
cool, je l'ai refait pour être sûr et j'ai quand même tout fait du texte. Cela a bien fonctionné et il était super facile d'ajouter rapidement des millions de documents historiques.
trench
@trench et reader: la seule exception est le type de données plus rapide "char", ce qui n'est pas le cas char, même de nos jours avec PostgreSQL 11+. Comme le guide de / type de données caractère dit « Le type "char"(notez les guillemets) est différent de char (1) en ce qu'il utilise un seul octet de stockage. Il est utilisé en interne dans les catalogues système comme un type d'énumération simpliste . » .
Peter Krauss
3
toujours valide avec pg11 en 2019: texte> varchar (n)> text_check> char (n)
Olivier Refalo
37

Sur le manuel PostgreSQL

Il n'y a pas de différence de performances entre ces trois types, à part un espace de stockage accru lors de l'utilisation du type à remplissage vierge et quelques cycles CPU supplémentaires pour vérifier la longueur lors du stockage dans une colonne à longueur limitée. Bien que le caractère (n) présente des avantages en termes de performances dans certains autres systèmes de base de données, il n'y en a pas dans PostgreSQL; en fait, le caractère (n) est généralement le plus lent des trois en raison de ses coûts de stockage supplémentaires. Dans la plupart des situations, le texte ou les caractères variant doivent être utilisés à la place.

J'utilise habituellement du texte

Références: http://www.postgresql.org/docs/current/static/datatype-character.html

un cheval sans nom
la source
23

À mon avis, varchar(n)a ses propres avantages. Oui, ils utilisent tous le même type sous-jacent et tout ça. Mais, il convient de souligner que les index dans PostgreSQL ont sa limite de taille de 2712 octets par ligne.

TL; DR: Si vous utilisez du texttype sans contrainte et avez des index sur ces colonnes, il est très possible que vous atteigniez cette limite pour certaines de vos colonnes et que vous obteniez une erreur lorsque vous essayez d'insérer des données mais en utilisant varchar(n), vous pouvez l'empêcher.

Quelques détails supplémentaires: Le problème ici est que PostgreSQL ne donne aucune exception lors de la création d'index pour le texttype ou varchar(n)nest supérieur à 2712. Cependant, il produira une erreur lorsqu'un enregistrement avec une taille compressée supérieure à 2712 sera inséré. Cela signifie que vous pouvez insérer facilement 100 000 caractères de chaîne composée de caractères répétitifs car elle sera compressée bien en dessous de 2712, mais vous ne pourrez peut-être pas insérer de chaîne de 4000 caractères car la taille compressée est supérieure à 2712 octets. En utilisant varchar(n)nn'est pas trop supérieur à 2712, vous êtes à l'abri de ces erreurs.

sotn
la source
Les erreurs postgres ultérieures lors de la tentative de création d'une indexation pour le texte ne fonctionnent que pour varchar (version sans le (n)). Testé uniquement avec des postgres intégrés.
arntg
2
En se référant à: stackoverflow.com/questions/39965834/… qui a un lien vers le wiki PostgreSQL: wiki.postgresql.org/wiki/… a une taille de ligne maximale de 400 Go, d'où il semble que la limite de 2712 octets par ligne indiquée soit incorrecte . Taille maximale pour une base de données? illimité (il existe des bases de données de 32 To) Taille maximale d'une table? 32 To Taille maximale pour une ligne? 400 Go Taille maximale pour un champ? 1 Go Nombre maximum de lignes dans une table? illimité
Bill Worthington
@BillWorthington Cependant, les chiffres que vous avez publiés ne tiennent pas compte de la mise en place d'index. 2712 octets concerne les limites maximales de btree, c'est un détail d'implémentation que vous ne pouvez pas trouver sur les documents. Cependant, vous pouvez facilement le tester vous-même ou simplement le rechercher sur Google en recherchant "la taille de la ligne d'index postgresql dépasse 2712 maximum pour l'index", par exemple.
2018 à 10h52
Je suis nouveau sur PostgeSQL, donc je ne suis pas l'expert. Je travaille sur un projet où je souhaite stocker des articles de presse dans une colonne d'un tableau. On dirait que le type de colonne de texte est ce que j'utiliserai. Une taille de ligne totale de 2712 octets semble beaucoup trop faible pour une base de données supposée être proche du même niveau qu'Oracle. Dois-je bien comprendre que vous faites référence à l'indexation d'un grand champ de texte? N'essayez pas de vous défier ou de vous disputer, essayez simplement de comprendre les vraies limites. S'il n'y a pas d'index impliqués, la limite de lignes serait-elle de 400 Go comme dans le wiki ?? Merci pour votre réponse rapide.
Bill Worthington
1
@BillWorthington Vous devriez faire des recherches sur la recherche en texte intégral. Vérifiez ce lien par exemple
sotn
18

text et varchar ont des conversions de types implicites différentes. Le plus grand impact que j'ai remarqué est la gestion des espaces de fin. Par exemple ...

select ' '::char = ' '::varchar, ' '::char = ' '::text, ' '::varchar = ' '::text

retourne true, false, trueet pas true, true, truecomme on pourrait s'y attendre.

bpd
la source
Comment est-ce possible? Si a = b et a = c alors b = c.
Lucas Silva
4

Un peu OT: Si vous utilisez Rails, le formatage standard des pages Web peut être différent. Pour les formulaires de saisie de données, les textcases défilent, mais les cases character varying(Rails string) sont sur une seule ligne. Les vues affichées sont aussi longues que nécessaire.

Greg
la source
2

Une bonne explication de http://www.sqlines.com/postgresql/datatypes/text :

La seule différence entre TEXT et VARCHAR (n) est que vous pouvez limiter la longueur maximale d'une colonne VARCHAR, par exemple, VARCHAR (255) ne permet pas d'insérer une chaîne de plus de 255 caractères.

TEXT et VARCHAR ont tous deux la limite supérieure à 1 Go, et il n'y a pas de différence de performances entre eux (selon la documentation PostgreSQL).

Chris Halcrow
la source
-1

character varying(n), varchar(n)- (les deux identiques). La valeur sera tronquée à n caractères sans déclencher d'erreur.

character(n), char(n)- (les deux identiques). de longueur fixe et se garnira de blancs jusqu'à la fin de la longueur.

text- Longueur illimitée.

Exemple:

Table test:
   a character(7)
   b varchar(7)

insert "ok    " to a
insert "ok    " to b

Nous obtenons les résultats:

a        | (a)char_length | b     | (b)char_length
----------+----------------+-------+----------------
"ok     "| 7              | "ok"  | 2
ofir_aghai
la source
5
Alors que MySQL tronquera silencieusement les données lorsque la valeur dépasse la taille de la colonne, PostgreSQL ne générera pas et générera une erreur "valeur trop longue pour le caractère variant (n)".
gsiems