MySQL: grande VARCHAR vs. TEXT?


847

Ho una tabella dei messaggi in MySQL che registra i messaggi tra utenti. A parte i tipici ID e tipi di messaggio (tutti i tipi interi) ho bisogno di salvare il testo del messaggio come VARCHAR o TEXT. Sto impostando un limite front-end di 3000 caratteri, il che significa che i messaggi non verrebbero mai inseriti nel db più a lungo di questo.

C'è una logica per andare con VARCHAR (3000) o TEXT? C'è qualcosa nello scrivere VARCHAR (3000) che sembra in qualche modo controintuitivo. Ho passato altri post simili su Stack Overflow ma sarebbe utile ottenere visualizzazioni specifiche per questo tipo di archiviazione dei messaggi comuni.


28
Un po 'vecchio, ma sono venuto qui perché ho riscontrato un problema che mi ha fatto riflettere su questo. Nel mio caso il mio modulo front-end era limitato a 2.000 caratteri, ma la codifica implicita nel mio metodo di archiviazione codificava caratteri internazionali come caratteri multipli (che apparentemente possono andare da 3 a 12 caratteri per carattere). Quindi i miei 2000 diventano improvvisamente fino a 24.000. Qualcosa su cui pensare ...
James S,

3
Ho trovato il testo molto più veloce per molti inserimenti simultanei.
Ray S.

1
@JamesS: utf8mb4 ...>. <
indivisibile

10
@RickJames considera di pubblicare una risposta aggiornata, piuttosto che chiudere la domanda
Yvette

3
@YvetteColomb - Ho aggiunto una risposta. Vorrei principalmente eliminare la risposta accettata perché non è aggiornata . Sono venuto al Q&A perché qualcuno stava citando informazioni errate, dicendo "754 voti positivi, quindi deve essere giusto". OK, ho modificato anche la risposta approvata. (Anche se sembra improprio.)
Rick James,

Risposte:


812
  • TEXTe BLOB può essere archiviato dalla tabella con la tabella che ha solo un puntatore alla posizione della memoria effettiva. La posizione in cui viene archiviato dipende da molte cose come la dimensione dei dati, la dimensione delle colonne, il formato riga e la versione di MySQL.

  • VARCHARè memorizzato in linea con la tabella. VARCHARè più veloce quando la dimensione è ragionevole, il cui compromesso sarebbe più veloce dipende dai tuoi dati e dal tuo hardware, vorresti confrontare uno scenario del mondo reale con i tuoi dati.


149
+1: VARCHAR (memorizzato in linea) è in genere più veloce SE i dati vengono recuperati frequentemente (inclusi nella maggior parte delle query). Tuttavia, per un grande volume di dati che non viene normalmente recuperato (ovvero non referenziato da alcuna query), potrebbe essere meglio non avere i dati memorizzati in linea. Esiste un limite superiore per la dimensione della riga, per i dati memorizzati in linea.
spencer7593,

22
@Pacerier: l'esatto vantaggio di evitare l'archiviazione "inline" è un aumento del numero di righe che possono essere archiviate in un blocco, il che significa che le righe della tabella occupano meno blocchi nella cache del buffer InnoDB (minore ingombro di memoria) e significano meno blocchi da trasferire da e verso disco (I / O ridotto). Tuttavia, questo è solo un vantaggio in termini di prestazioni se le colonne archiviate "fuori riga" non sono ampiamente referenziate dalle query. Se quelle colonne "fuori riga" sono referenziate dalla maggior parte delle query, il vantaggio svanisce ampiamente. In linea è preferibile se le colonne si adattano alla dimensione massima delle righe e sono spesso referenziate.
spencer7593

232
"VARCHAR è più veloce quando la dimensione è ragionevole". Qual è un numero "ragionevole" di caratteri, 100? 1000? 100.000?
Tim Peterson,

126
Questa risposta non è corretta per InnoDB. Sia VARCHAR che BLOB / TEXT sono memorizzati in linea con altre colonne se il valore su una determinata riga si adatta alle dimensioni della pagina (16 KB e ogni pagina deve contenere almeno due righe). Se la stringa è troppo grande per questo, trabocca a pagine aggiuntive. Vedi mysqlperformanceblog.com/2010/02/09/blob-storage-in-innodb per una spiegazione dettagliata.
Bill Karwin,

15
@BillKarwin ... Se sto capendo correttamente, non ci dovrebbero essere differenze di prestazioni tra varchare blob/ textsu InnoDB per piccoli elementi di testo? Così sarebbe quindi saggio fare solo ogni varcharun texttipo e lasciare che il DB gestire la vs. troppo pieno in linea?
ryvantage

475

Puoi prevedere quanto sarebbe lungo l'input dell'utente?

VARCHAR (X)

Caso: nome utente, e-mail, paese, oggetto, password


TESTO

Caso: messaggi, e-mail, commenti, testo formattato, html, codice, immagini, collegamenti


MEDIUMTEXT

Cassa: corpi json di grandi dimensioni, libri di lunghezza medio-corta, corde in CSV


LONGTEXT

Caso: libri di testo, programmi, anni di file di log, harry potter e il calice di fuoco, registrazione della ricerca scientifica


8
La prevedibilità è davvero un elemento secondario qui. In realtà è la lunghezza massima prevista che dovrebbe essere il fattore decisivo. Gli articoli che ritieni più prevedibili sono solo così perché sono più brevi degli altri.
Andrew Barber,

30
@ andrew-barber Questo è il mio punto però. Tutti gli altri post spiegano bene le differenze ma non le situazioni in cui devi effettivamente scegliere tra i due. Stavo cercando di sottolineare che usare varchar come prevedibilmente breve è una buona scelta e usare il testo per un tempo arbitrariamente lungo è una buona scelta.
Michael J. Calkins,

1
Se tutte le colonne sono brevi e prevedibili (ad es. Indirizzo MAC, IMEI, ecc ... sono cose che non cambiano mai), usa le colonne CHAR e puoi fissare le dimensioni della riga, il che dovrebbe velocizzare notevolmente le cose se usi MyISAM, possibilmente anche InnoDb anche se non ne sono sicuro.
Matt,

1
@ MichaelJ.Calkins Cosa che è successo in MySQL 5.6. Ora hai anche la ricerca full-text in InnoDB. Vedi dev.mysql.com/doc/refman/5.6/en/fulltext-search.html
PhoneixS

7
Limiti di caratteri: TINYTEXT: 255; TESTO: 65.535; MEDIUMTEXT: 16.777.215; LUNGHEZZA: 4.294.967,29.
Victor Stoddard,

219

Giusto per chiarire la migliore pratica:

  1. I messaggi in formato testo dovrebbero essere quasi sempre archiviati come TESTO (finiscono per essere arbitrariamente lunghi)

  2. Gli attributi di stringa devono essere archiviati come VARCHAR (il nome utente di destinazione, l'oggetto, ecc ...).

Capisco che hai un limite per il front-end, che è ottimo fino a quando non lo è. * grin * Il trucco è pensare al DB come separato dalle applicazioni che si collegano ad esso. Solo perché un'applicazione pone un limite ai dati, ciò non significa che i dati siano intrinsecamente limitati.

Cosa c'è nei messaggi stessi che li costringe a non essere mai più di 3000 caratteri? Se è solo un vincolo di applicazione arbitrario (ad esempio, per una casella di testo o qualcosa del genere), utilizzare un TEXTcampo a livello di dati.


Che cosa significa "il che è fantastico finché non lo è"? A cosa si riferisce "non"?
Pacerier,

7
@Pacerier Per darti un esempio del "non è" su cui probabilmente è James: prendi ad esempio Twitter, che fino a poco tempo fa aveva un limite di 140 caratteri sui PM. Decisero che non era più ragionevole e scelsero di rimuovere completamente quel limite. Se non avessero pensato in anticipo a quello (cosa che sono abbastanza sicuro che probabilmente hanno fatto ...) si sarebbero imbattuti nello scenario delineato sopra.
PaulSkinner,

9
Sto solo creando il nostro nuovo database e ho pensato che nessuno potesse mettere più di 2000 caratteri nelle nostre piccole caselle di commento e poi, come osserva James, stasera improvvisamente "non era ok" perché un utente ha passato un commento molto valido che era lungo 2600 caratteri. Avevo usato varchar (2000) pensando che non sarebbe potuto durare di più, e mi sbagliavo. quindi sì, è fantastico fino a quando non lo è. Nel nostro caso ci sono voluti solo pochi giorni per manifestarsi. La regola qui sotto, Michael J. Calkins, penso che userò d'ora in poi. testo per messaggi, commenti.
Lizardx,

1
@Pacerier "il che è fantastico fino a quando non lo è". In altre parole, funziona quasi sempre ed è meraviglioso ... tranne quelle situazioni eccezionali in cui non è così eccezionale.
Espiazione limitata il

@Pacerier un altro esempio interessante è menzionato nei commenti della risposta selezionata, fondamentalmente aveva un limite front-end di 2.000 caratteri, ma i personaggi introdotti erano in una tabella codici che in realtà utilizzava più byte delle lettere normali, il suo database finiva per avere bisogno di spazio per 24k caratteri solo perché doveva tenere conto della dimensione effettiva dei byte dei caratteri introdotti.
RaptorX,

32

Disclaimer: non sono un esperto di MySQL ... ma questa è la mia comprensione dei problemi.

Penso che TEXT sia memorizzato al di fuori della riga mysql, mentre penso che VARCHAR sia memorizzato come parte della riga. C'è una lunghezza massima di riga per le righe mysql .. quindi puoi limitare la quantità di altri dati che puoi archiviare in una riga usando VARCHAR.

Anche a causa del fatto che VARCHAR fa parte della riga, sospetto che le query che guardano quel campo saranno leggermente più veloci di quelle che usano un blocco TEXT.


38
Il limite di lunghezza della riga è 65.535 byte [ dev.mysql.com/doc/refman/5.0/en/column-count-limit.html ]. Se la tua colonna è codificata in utf8, ciò significa che una varcharcolonna di 3000 caratteri può richiedere fino a 9000 byte.
Jan Fabry,

7
I caratteri UTF-8 possono avere un massimo di 4 byte, quindi penso che tu intendessi 12.000 byte (a meno che non ci sia qualcosa di MySQL che non capisco qui).
raylu,

13
@raylu UTF-8 di MySQL è "falso UTF-8" in quanto supporta solo 3 byte per carattere massimo, quindi non c'è modo di memorizzare direttamente i caratteri unicode oltre l'aereo BMP nell'UTF-8 di MySQL. Questo problema è stato risolto in MySQL 5.5.
Pacerier,

2
Credo che questa affermazione sia valida solo per MyISAM. Non riesco a trovare una fonte definitiva, ma credo che anche i negozi InnoDB siano in TEXTlinea nella tabella.
dotancohen,

2
@dotancohen Ho trovato qui una fonte che spiega che l'archiviazione di dati a lunghezza variabile utilizzando InnoDB può variare (può essere archiviata esternamente o in linea all'interno della riga) mysqlserverteam.com/externally-stored-fields-in-innodb
KiX Ortillan

30

Risposta breve: nessuna differenza pratica, prestazionale o di archiviazione.

Risposta lunga:

Non esiste sostanzialmente alcuna differenza (in MySQL) tra VARCHAR(3000)(o qualsiasi altro limite di grandi dimensioni) e TEXT. Il primo troncerà a 3000 caratteri ; quest'ultimo verrà troncato a 65535 byte . (Faccio una distinzione tra byte e caratteri perché un personaggio può prendere più byte.)

Per limiti minori VARCHAR, ci sono alcuni vantaggi TEXT.

  • "più piccolo" significa 191, 255, 512, 767 o 3072, ecc., a seconda della versione, del contesto e CHARACTER SET.
  • INDEXessono limitati nella dimensione di una colonna che può essere indicizzata. (767 o 3072 byte ; dipende dalla versione e dalle impostazioni)
  • Tabelle intermedie create da complessi SELECTs sono gestite in due modi diversi: MEMORIA (più veloce) o MyISAM (più lenta). Quando sono coinvolte colonne "grandi", la tecnica più lenta viene automaticamente selezionata. (Cambiamenti significativi in ​​arrivo nella versione 8.0; quindi questo punto elenco è soggetto a modifiche.)
  • Relativamente all'elemento precedente, tutti i TEXTtipi di dati (invece di VARCHAR) passano direttamente a MyISAM. Cioè, TINYTEXTè automaticamente peggio per le tabelle temporanee generate rispetto all'equivalente VARCHAR. (Ma questo porta la discussione in una terza direzione!)
  • VARBINARYè come VARCHAR; BLOBè come TEXT.

Confutazione ad altre risposte

La domanda originale poneva una cosa (quale tipo di dati usare); la risposta accettata ha risposto a qualcos'altro (archiviazione non registrata). Quella risposta non è più aggiornata.

Quando questo thread è stato avviato e risposto, c'erano solo due "formati di riga" in InnoDB. Poco dopo furono introdotti altri due formati ( DYNAMICe COMPRESSED).

Il percorso di archiviazione per TEXTe VARCHAR()si basa sulla dimensione , non sul nome del tipo di dati . Per una discussione aggiornata sull'archiviazione on / off-record di colonne di testo / BLOB di grandi dimensioni, vedere questo .


1
Qualche buona idea qui. Questa dovrebbe essere la risposta accettata.
Kosta Kontos,

2
@KostaKontos - Grazie per gli elogi e la correzione dell'errore di battitura. Quando vedrò la necessità di una risposta migliore, aggiungerò una risposta, anche se 8 anni e 800 voti troppo tardi.
Rick James,

7

Le risposte precedenti non insistono abbastanza sul problema principale: anche in domande molto semplici come

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

può essere richiesta una tabella temporanea e, se VARCHARè coinvolto un campo, viene convertito in un CHARcampo nella tabella temporanea. Quindi se nella tua tabella hai scritto 500.000 righe con un VARCHAR(65000)campo, questa sola colonna userà 6.5 * 5 * 10 ^ 9 byte. Tali tabelle temporanee non possono essere gestite in memoria e vengono scritte su disco. Ci si può aspettare che l'impatto sia catastrofico.

Fonte (con metriche): https://nicj.net/mysql-text-vs-varchar-performance/ (si riferisce alla gestione di TEXTvs VARCHARnel motore di archiviazione MyISAM "standard" (?). Potrebbe essere diverso in altri, ad es. InnoDB.)


3
InnoDB: lo stesso vale per la versione 5.7. Con 8.0, le temperature varchar sono di lunghezza variabile.
Rick James,

3

C'è una GRANDE differenza tra VARCHAR e TEXT. Mentre i campi VARCHAR possono essere indicizzati, i campi TEXT non possono. I campi di tipo VARCHAR sono memorizzati in linea mentre TEXT sono archiviati offline, solo i puntatori ai dati TEXT sono effettivamente memorizzati nei record.

Se devi indicizzare il tuo campo per una ricerca più veloce, aggiorna o elimina rispetto a VARCHAR, non importa quanto sia grande. Un VARCHAR (10000000) non sarà mai lo stesso di un campo TEXT perché questi due tipi di dati sono di natura diversa.

  • Se si utilizza il campo solo per l'archiviazione
  • non ti interessa il ripristino della velocità dei dati
  • ti interessa la velocità ma utilizzerai l'operatore '% LIKE%' nella tua query di ricerca, quindi l'indicizzazione non sarà di grande aiuto
  • non è possibile prevedere un limite per la lunghezza dei dati

che andare per TEXT.


Informazioni parzialmente fuorvianti: le colonne TEXT non possono essere indicizzate nella loro interezza. Quando si include una colonna TEXT nell'indice, è necessario specificare la lunghezza. Inoltre, i VARCHAR non possono essere indicizzati nella loro interezza nel caso dei VARCHAR> 255 poiché esiste una lunghezza massima nella dimensione dell'indice.
eRadical

2

Varchar è per piccoli dati come indirizzi e-mail, mentre Testo è per dati molto più grandi come articoli di notizie, Blob per dati binari come immagini.

Le prestazioni di Varchar sono più potenti perché vengono eseguite completamente dalla memoria, ma non sarà così se i dati sono troppo grandi come varchar(4000)ad esempio.

Il testo, d'altra parte, non si attacca alla memoria ed è influenzato dalle prestazioni del disco, ma è possibile evitarlo separando i dati di testo in una tabella separata e applicare una query di join sinistro per recuperare i dati di testo.

Il BLOB è molto più lento, quindi usalo solo se non hai molti dati come 10000 immagini che costeranno 10000 record.

Segui questi suggerimenti per la massima velocità e prestazioni:

  1. Usa varchar per nome, titoli, e-mail

  2. Usa testo per dati di grandi dimensioni

  3. Separare il testo in diverse tabelle

  4. Usa le query Left Join su un ID come un numero di telefono

  5. Se hai intenzione di usare Blob, applica gli stessi suggerimenti del testo

Ciò farà sì che le query costino millisecondi su tabelle con dati> 10 M e dimensioni garantite fino a 10 GB.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.