MySQL: grand VARCHAR vs TEXT?

847

J'ai une table de messages dans MySQL qui enregistre les messages entre les utilisateurs. Mis à part les identifiants et les types de messages typiques (tous les types entiers), je dois enregistrer le texte du message en tant que VARCHAR ou TEXT. Je fixe une limite frontale de 3000 caractères, ce qui signifie que les messages ne seront jamais insérés dans la base de données plus longtemps que cela.

Y a-t-il une justification pour aller avec VARCHAR (3000) ou TEXT? Il y a quelque chose à propos de l'écriture de VARCHAR (3000) qui semble quelque peu contre-intuitif. J'ai lu d'autres articles similaires sur Stack Overflow, mais ce serait bien d'avoir des vues spécifiques à ce type de stockage de messages courants.

À M
la source
28
Un peu vieux, mais je suis venu ici parce que j'ai rencontré un problème qui m'a fait réfléchir. Dans mon cas, mon formulaire frontal était limité à 2 000 caractères, mais le codage implicite dans ma méthode de stockage codait les caractères internationaux en plusieurs caractères (ce qui peut apparemment varier de 3 à 12 par caractère). Donc mes 2 000 deviennent soudainement jusqu'à 24 000. Quelque chose à penser ...
James S
3
J'ai trouvé que le texte était beaucoup plus rapide pour de nombreuses insertions simultanées.
Ray S.
1
@JamesS: utf8mb4 ...>. <
indivisible
10
@RickJames envisage de publier une réponse mise à jour, plutôt que de fermer la question
Yvette
3
@YvetteColomb - J'ai ajouté une réponse. Je voudrais surtout me débarrasser de la réponse acceptée car elle est obsolète . Je suis venu au Q & A parce que quelqu'un citait des informations incorrectes, disant "754 votes positifs, donc ça doit être vrai". OK, j'ai également modifié la réponse approuvée. (Bien que cela semble inapproprié.)
Rick James

Réponses:

812
  • TEXTet BLOB peut être stocké hors de la table, la table ayant simplement un pointeur vers l'emplacement du stockage réel. L'endroit où il est stocké dépend de beaucoup de choses comme la taille des données, la taille des colonnes, row_format et la version MySQL.

  • VARCHARest stocké en ligne avec la table. VARCHARest plus rapide lorsque la taille est raisonnable, dont le compromis serait plus rapide en fonction de vos données et de votre matériel, vous voudriez comparer un scénario réel avec vos données.

MindStalker
la source
149
+1: VARCHAR (stocké en ligne) est généralement plus rapide SI les données sont fréquemment récupérées (incluses dans la plupart des requêtes). Cependant, pour un grand volume de données qui n'est pas normalement récupéré (c'est-à-dire qui n'est référencé par aucune requête), il peut être préférable de ne pas stocker les données en ligne. Il existe une limite supérieure pour la taille des lignes, pour les données stockées en ligne.
spencer7593
22
@Pacerier: l'avantage exact d'éviter le stockage "en ligne" est une augmentation du nombre de lignes pouvant être stockées dans un bloc, ce qui signifie que les lignes de la table occupent moins de blocs dans le cache de tampon InnoDB (encombrement mémoire plus petit), et signifie moins blocs à transférer vers et depuis le disque (E / S réduites). Mais, ce n'est un avantage en termes de performances que si les colonnes stockées "hors ligne" ne sont en grande partie pas référencées par les requêtes. Si ces colonnes "hors ligne" sont référencées par la plupart des requêtes, cet avantage s'évapore largement. Inline est préférable si les colonnes tiennent dans la taille de ligne maximale et sont fréquemment référencées.
spencer7593
232
"VARCHAR est plus rapide lorsque la taille est raisonnable". Qu'est-ce qu'un nombre "raisonnable" de caractères, 100? 1000? 100 000?
tim peterson
126
Cette réponse n'est pas correcte pour InnoDB. VARCHAR et BLOB / TEXT sont stockés en ligne avec d'autres colonnes si la valeur sur une ligne donnée correspond à la taille de la page (16 Ko et chaque page doit contenir au moins deux lignes). Si la chaîne est trop grande pour cela, elle déborde sur des pages supplémentaires. Voir mysqlperformanceblog.com/2010/02/09/blob-storage-in-innodb pour une explication détaillée.
Bill Karwin
15
@BillKarwin ... Si je comprends bien, il ne devrait pas y avoir de différence de performances entre varcharet blob/ textsur InnoDB pour les petits éléments de texte? Alors , serait - il alors juste rendre sage tout varcharun texttype et laisser le DB gérer le trop - plein de rapport en ligne?
ryvantage
475

Pouvez-vous prévoir la durée de la saisie utilisateur?

VARCHAR (X)

Cas: nom d'utilisateur, email, pays, sujet, mot de passe


TEXTE

Cas: messages, e-mails, commentaires, texte formaté, html, code, images, liens


MOYENTEXTE

Boîtier: grands corps json, livres courts à moyens, cordes csv


LONGTEXT

Cas: manuels, programmes, années de fichiers journaux, harry potter et la coupe de feu, journalisation de la recherche scientifique

Michael J. Calkins
la source
8
La prévisibilité est vraiment un élément secondaire ici. C'est en fait la longueur maximale prévue qui devrait être le facteur décisif. Les éléments que vous mentionnez comme plus prévisibles ne le sont que parce qu'ils sont plus courts que les autres.
Andrew Barber
30
@ andrew-barber C'est mon point cependant. Tous les autres articles expliquent bien les différences mais pas les situations où vous devez réellement choisir entre les deux. J'essayais de souligner que l'utilisation de varchar pour une durée prévisible est un bon choix et que l'utilisation de texte pour une durée arbitraire est un bon choix.
Michael J.Calkins
1
Si toutes les colonnes sont courtes et prévisibles (ex: adresse MAC, IMEI, etc ... sont des choses qui ne changent jamais) alors utilisez les colonnes CHAR et vous pouvez faire votre taille de ligne fixe, ce qui devrait accélérer considérablement les choses si vous utilisez MyISAM, éventuellement aussi InnoDb bien que je n'en sois pas sûr.
Matt
1
@ MichaelJ.Calkins Chose qui s'est produite dans MySQL 5.6. Maintenant, vous avez également une recherche plein texte dans InnoDB. Voir dev.mysql.com/doc/refman/5.6/en/fulltext-search.html
PhoneixS
7
Limites de caractères: TINYTEXT: 255; TEXTE: 65 535; MOYENTEXTE: 16 777 215; LONGTEXTE: 4 294 967,29.
Victor Stoddard
219

Juste pour clarifier la meilleure pratique:

  1. Les messages au format texte doivent presque toujours être stockés sous forme de texte (ils finissent par être arbitrairement longs)

  2. Les attributs de chaîne doivent être stockés en tant que VARCHAR (le nom d'utilisateur de destination, le sujet, etc ...).

Je comprends que vous avez une limite avant, ce qui est excellent jusqu'à ce qu'elle ne le soit pas. * sourire * L'astuce consiste à penser la base de données comme distincte des applications qui s'y connectent. Ce n'est pas parce qu'une application limite les données que les données sont intrinsèquement limitées.

En quoi les messages eux-mêmes les obligent-ils à ne jamais dépasser 3000 caractères? S'il s'agit simplement d'une contrainte d'application arbitraire (par exemple, pour une zone de texte ou quelque chose), utilisez un TEXTchamp au niveau de la couche de données.

James
la source
Que signifie «ce qui est génial jusqu'à ce qu'il ne l'est pas»? À quoi fait référence «n'est pas»?
Pacerier
7
@Pacerier Pour vous donner un exemple du "n'est pas" que James est probablement sur: Prenez par exemple Twitter, qui jusqu'à très récemment avait une limite de 140 caractères sur les PM. Ils ont décidé qu'il n'était plus raisonnable et ont choisi de supprimer complètement cette limite. S'ils n'y avaient pas pensé à l'avance (ce que je suis sûr qu'ils ont probablement fait ...), ils se seraient heurtés au scénario décrit ci-dessus.
PaulSkinner
9
Je suis en train de mettre en place notre nouvelle base de données, et je pensais que personne ne pourrait mettre plus de 2000 caractères dans nos minuscules boîtes de commentaires, puis, comme le note James, ce soir, tout à coup "ce n'était pas bien" parce qu'un utilisateur a mis un commentaire très valide de 2 600 caractères. J'avais utilisé varchar (2000) en pensant que cela ne pouvait pas durer plus longtemps, et je me trompais. donc oui, c'est génial jusqu'à ce qu'il ne soit pas. Dans notre cas, cela n'a pris que quelques jours pour se manifester. La règle ci-dessous, Michael J. Calkins, je pense que je vais utiliser à partir de maintenant. texte pour messages, commentaires.
Lizardx
1
@Pacerier "qui est génial jusqu'à ce qu'il ne soit pas génial". En d'autres termes, cela fonctionne presque tout le temps et est merveilleux ... sauf dans les situations exceptionnelles où ce n'est pas si bon.
Expiation limitée
@Pacerier un autre exemple intéressant est mentionné dans les commentaires de la réponse sélectionnée, fondamentalement, il avait une limite frontale de 2000 caractères mais les caractères introduits étaient dans une page de code qui en réalité utilisait plus d'octets que les lettres normales, sa base de données a fini par avoir besoin d'espace pour 24k caractères simplement parce qu'il devait tenir compte de la taille réelle des octets des caractères introduits.
RaptorX
32

Avertissement: je ne suis pas un expert MySQL ... mais c'est ma compréhension des problèmes.

Je pense que TEXT est stocké en dehors de la ligne mysql, alors que je pense que VARCHAR est stocké dans le cadre de la ligne. Il y a une longueur de ligne maximale pour les lignes mysql .. vous pouvez donc limiter la quantité d'autres données que vous pouvez stocker dans une ligne en utilisant le VARCHAR.

En raison également de la présence de VARCHAR dans la ligne, je soupçonne que les requêtes regardant ce champ seront légèrement plus rapides que celles utilisant un morceau TEXT.

Michael Anderson
la source
38
La limite de longueur de ligne est de 65 535 octets [ dev.mysql.com/doc/refman/5.0/en/column-count-limit.html ]. Si votre colonne est codée en utf8, cela signifie qu'une varcharcolonne de 3 000 caractères peut prendre jusqu'à 9 000 octets.
Jan Fabry
7
Les caractères UTF-8 peuvent aller jusqu'à 4 octets, donc je pense que vous vouliez 12 000 octets (à moins qu'il y ait quelque chose MySQL que je ne comprends pas ici).
raylu
13
L'UTF-8 de @raylu MySQL est un "faux UTF-8" en ce qu'il ne prend en charge que 3 octets par caractère maximum, il n'y a donc aucun moyen de stocker directement des caractères Unicode au-delà du plan BMP dans l'UTF-8 de MySQL. Ceci est corrigé dans MySQL 5.5.
Pacerier
2
Je crois que cette affirmation n'est valable que pour MyISAM. Je ne trouve pas de source définitive mais je crois que InnoDB stocke également en TEXTligne dans le tableau.
dotancohen
2
@dotancohen J'ai trouvé une source ici expliquant que le stockage de données de longueur variable en utilisant InnoDB peut varier (peut être stocké en externe ou en ligne dans la ligne) mysqlserverteam.com/externally-stored-fields-in-innodb
KiX Ortillan
30

Réponse courte: Aucune différence pratique, de performance ou de stockage.

Longue réponse:

Il n'y a essentiellement aucune différence (dans MySQL) entre VARCHAR(3000)(ou toute autre grande limite) et TEXT. Le premier tronquera à 3000 caractères ; ce dernier sera tronqué à 65 535 octets . (Je fais une distinction entre octets et caractères car un caractère peut prendre plusieurs octets.)

Pour des limites plus petites dans VARCHAR, il y a certains avantages par rapport à TEXT.

  • "plus petit" signifie 191, 255, 512, 767 ou 3072, etc., selon la version, le contexte et CHARACTER SET.
  • INDEXessont limités dans la taille d'une colonne pouvant être indexée. (767 ou 3072 octets ; cela dépend de la version et des paramètres)
  • Les tables intermédiaires créées par Complex SELECTssont gérées de deux manières différentes - MEMORY (plus rapide) ou MyISAM (plus lent). Lorsque de «grandes» colonnes sont impliquées, la technique la plus lente est automatiquement sélectionnée. (Modifications importantes à venir dans la version 8.0; donc cette puce peut être modifiée.)
  • Par rapport à l'élément précédent, tous les TEXTtypes de données (par opposition à VARCHAR) passent directement à MyISAM. Autrement dit, TINYTEXTest automatiquement pire pour les tables temporaires générées que l'équivalent VARCHAR. (Mais cela entraîne la discussion dans une troisième direction!)
  • VARBINARYest comme VARCHAR; BLOBc'est comme TEXT.

Réfutation à d'autres réponses

La question d'origine demandait une chose (quel type de données utiliser); la réponse acceptée a répondu à autre chose (stockage hors enregistrement). Cette réponse est désormais obsolète.

Lorsque ce thread a été démarré et a répondu, il n'y avait que deux "formats de ligne" dans InnoDB. Peu de temps après, deux autres formats ( DYNAMICet COMPRESSED) ont été introduits.

L'emplacement de stockage pour TEXTet VARCHAR()est basé sur la taille et non sur le nom du type de données . Pour une discussion mise à jour sur le stockage on / off-record de grandes colonnes de texte / blob, voir ceci .

Rick James
la source
1
Quelques bonnes informations ici. Ce devrait être la réponse acceptée.
Kosta Kontos
2
@KostaKontos - Merci pour les éloges et la correction de faute de frappe. Quand je verrai le besoin d'une meilleure réponse, j'ajouterai une réponse, même si 8 ans et 800 votes positifs trop tard.
Rick James
7

Les réponses précédentes n'insistent pas assez sur le problème principal: même dans des requêtes très simples comme

(SELECT t2.* FROM t1, t2 WHERE t2.id = t1.id ORDER BY t1.id) 

une table temporaire peut être requise, et si un VARCHARchamp est impliqué, il est converti en un CHARchamp dans la table temporaire. Donc, si vous avez dans votre tableau 500 000 lignes avec un VARCHAR(65000)champ, cette colonne utilisera à elle seule 6,5 * 5 * 10 ^ 9 octets. Ces tables temporaires ne peuvent pas être gérées en mémoire et sont écrites sur le disque. L'impact peut être catastrophique.

Source (avec métriques): https://nicj.net/mysql-text-vs-varchar-performance/ (Il s'agit de la gestion des TEXTvs VARCHARdans le moteur de stockage MyISAM "standard" (?). Cela peut être différent dans d'autres, par exemple, InnoDB.)

Max
la source
3
InnoDB: La même chose s'applique à la version 5.7. Avec 8.0, les temps varchar sont de longueur variable.
Rick James
3

Il y a une énorme différence entre VARCHAR et TEXT. Alors que les champs VARCHAR peuvent être indexés, les champs TEXT ne le peuvent pas. Les champs de type VARCHAR sont stockés en ligne tandis que TEXT est stocké hors ligne, seuls les pointeurs vers les données TEXT sont réellement stockés dans les enregistrements.

Si vous devez indexer votre champ pour une recherche, une mise à jour ou une suppression plus rapide que pour VARCHAR, quelle que soit sa taille. Un VARCHAR (10000000) ne sera jamais identique à un champ TEXT car ces deux types de données sont de nature différente.

  • Si vous utilisez votre champ uniquement pour l'archivage
  • vous ne vous souciez pas du retour de la vitesse des données
  • vous vous souciez de la vitesse mais vous utiliserez l'opérateur '% LIKE%' dans votre requête de recherche, donc l'indexation n'aidera pas beaucoup
  • vous ne pouvez pas prédire une limite de la longueur des données

que d'aller pour TEXT.

Viktor Joras
la source
Informations partiellement trompeuses: les colonnes TEXT ne peuvent pas être indexées dans leur intégralité. Lorsque vous incluez une colonne TEXT dans l'index, vous devez spécifier la longueur. Les VARCHARs ne peuvent pas non plus être indexés dans leur intégralité dans le cas de VARCHARs> 255 car il y a une longueur maximale sur la taille de l'index.
eRadical
2

Varchar est pour les petites données comme les adresses e-mail, tandis que Text est pour les données beaucoup plus importantes comme les articles de nouvelles, Blob pour les données binaires telles que les images.

Les performances de Varchar sont plus puissantes car elles s'exécutent complètement à partir de la mémoire, mais ce ne sera pas le cas si les données sont trop volumineuses comme varchar(4000)par exemple.

Le texte, en revanche, ne colle pas à la mémoire et est affecté par les performances du disque, mais vous pouvez éviter cela en séparant les données de texte dans une table distincte et en appliquant une requête de jointure gauche pour récupérer les données de texte.

Blob est beaucoup plus lent, alors n'utilisez-le que si vous n'avez pas beaucoup de données comme 10000 images qui coûteront 10000 enregistrements.

Suivez ces conseils pour une vitesse et des performances maximales:

  1. Utilisez varchar pour le nom, les titres, les e-mails

  2. Utiliser du texte pour des données volumineuses

  3. Texte séparé dans différents tableaux

  4. Utiliser les requêtes de jointure gauche sur un ID tel qu'un numéro de téléphone

  5. Si vous allez utiliser Blob, appliquez les mêmes conseils que dans Text

Ainsi, les requêtes coûteront des millisecondes sur des tables avec des données> 10 M et une taille jusqu'à 10 Go garantie.

Creative87
la source