MySQL: VARCHAR grande vs. texto?

847

Eu tenho uma tabela de mensagens no MySQL que registra mensagens entre usuários. Além dos IDs e tipos de mensagens típicos (todos os tipos de números inteiros), preciso salvar o texto da mensagem real como VARCHAR ou TEXT. Estou definindo um limite de 3000 caracteres no front-end, o que significa que as mensagens nunca seriam inseridas no banco de dados por mais tempo que isso.

Existe uma justificativa para usar o VARCHAR (3000) ou o TEXT? Há algo sobre escrever VARCHAR (3000) que parece um pouco contra-intuitivo. Já passei por outras postagens semelhantes no Stack Overflow, mas seria bom obter visualizações específicas para esse tipo de armazenamento comum de mensagens.

Tom
fonte
28
Um pouco velho, mas vim para cá porque tive um problema que me fez pensar sobre isso. No meu caso, meu formulário de front-end estava limitado a 2.000 caracteres, mas a codificação implícita no meu método de armazenamento codificava caracteres internacionais como vários caracteres (que aparentemente podem variar de 3 a 12 por caractere). Então meus 2.000 se tornam repentinamente 24.000. Algo para pensar ...
James S
3
Eu achei o texto significativamente mais rápido para muitas inserções simultâneas.
Ray S.
1
@JamesS: utf8mb4 ...>. <
indivisível
10
@RickJames considerar a publicação de uma resposta atualizado, ao invés de perto a questão
Yvette
3
@YvetteColomb - adicionei uma resposta. Gostaria principalmente de me livrar da resposta aceita porque está desatualizada . Eu vim para a sessão de perguntas e respostas porque alguém estava citando informações incorretas, dizendo "754 votos positivos, então deve estar certo". OK, também editei a resposta aprovada. (Apesar de que se sente inadequado.)
Rick James

Respostas:

812
  • TEXTe BLOB pode ser armazenado fora da mesa com a tabela apenas com um ponteiro para o local do armazenamento real. O local de armazenamento depende de várias coisas, como tamanho dos dados, tamanho das colunas, formato da linha e versão do MySQL.

  • VARCHARé armazenado em linha com a tabela. VARCHARé mais rápido quando o tamanho é razoável, cuja troca seria mais rápida depende dos seus dados e do seu hardware, você desejaria comparar um cenário do mundo real com seus dados.

MindStalker
fonte
149
+1: VARCHAR (armazenado em linha) geralmente é mais rápido se os dados são frequentemente recuperados (incluídos na maioria das consultas). No entanto, para um grande volume de dados que normalmente não é recuperado (ou seja, não é referenciado por nenhuma consulta), pode ser melhor não ter os dados armazenados em linha. Há um limite superior no tamanho da linha, para dados armazenados em linha.
precisa saber é o seguinte
22
@Pacerier: o benefício exato de evitar o armazenamento "em linha" é um aumento no número de linhas que podem ser armazenadas em um bloco, o que significa que as linhas da tabela ocupam menos blocos no cache do buffer InnoDB (menor espaço de memória) e significa menos blocos a serem transferidos para e do disco (E / S reduzida). Porém, isso é apenas um benefício de desempenho se as colunas armazenadas "fora da linha" não forem referenciadas por consultas. Se essas colunas "fora de linha" são referenciadas pela maioria das consultas, esse benefício evapora bastante. Inline é preferível se as colunas couberem no tamanho máximo de linhas e forem frequentemente referenciadas.
precisa saber é o seguinte
232
"VARCHAR é mais rápido quando o tamanho é razoável". O que é um número "razoável" de caracteres, 100? 1000? 100.000?
tim Peterson
126
Esta resposta não está correta para o InnoDB. VARCHAR e BLOB / TEXT são armazenados em linha com outras colunas se o valor em uma determinada linha couber no tamanho da página (16 KB e cada página deve conter pelo menos duas linhas). Se a sequência for muito grande para isso, ela excederá o limite para páginas adicionais. Veja mysqlperformanceblog.com/2010/02/09/blob-storage-in-innodb para uma explicação detalhada.
Bill Karwin
15
@ BillKarwin ... Se estou entendendo corretamente, não deve haver diferença de desempenho entre varchare blob/ textno InnoDB para pequenos itens de texto? Então seria então aconselhável apenas para fazer de cada varcharum texttipo e deixar o DB gerir o vs. estouro em linha?
ryvantage
475

Você pode prever quanto tempo a entrada do usuário seria?

VARCHAR (X)

Caso: nome de usuário, email, país, assunto, senha


TEXTO

Caso: mensagens, emails, comentários, texto formatado, html, código, imagens, links


MEDIUMTEXT

Case: grandes corpos json, livros de tamanho curto a médio, strings csv


LONGTEXT

Caso: livros didáticos, programas, anos de arquivos de registros, harry potter e o cálice de fogo, registro de pesquisas científicas

Michael J. Calkins
fonte
8
A previsibilidade é realmente um item secundário aqui. Na verdade, é o comprimento máximo esperado que deve ser o fator decisivo. Os itens que você menciona como mais previsíveis são apenas dessa maneira porque são mais curtos que os outros.
Andrew Barber
30
@ Andrew-barbeiro Esse é o meu ponto. Todas as outras postagens explicam bem sobre as diferenças, mas não sobre as situações em que você realmente precisa fazer uma escolha entre as duas. Eu estava tentando apontar que usar varchar por um tempo previsivelmente curto é uma boa opção e usar texto por um período arbitrariamente longo é uma boa escolha.
Michael J. Calkins
1
Se todas as colunas forem curtas e previsíveis (por exemplo: endereço MAC, IMEI, etc ... são coisas que nunca mudam), use as colunas CHAR e você poderá corrigir o tamanho da sua linha, o que deve acelerar consideravelmente as coisas se você estiver usando o MyISAM, possivelmente também InnoDb, embora eu não tenha certeza.
Matt
1
@ MichaelJ.Calkins O que aconteceu no MySQL 5.6. Agora você também tem pesquisa de texto completo no InnoDB. Veja dev.mysql.com/doc/refman/5.6/en/fulltext-search.html
PhoneixS
7
Limites de caracteres: TINYTEXT: 255; TEXTO: 65.535; MEDIUMTEXT: 16.777.215; LONGTEXT: 4.294.967,29.
Victor Stoddard
219

Apenas para esclarecer as melhores práticas:

  1. As mensagens em formato de texto quase sempre devem ser armazenadas como TEXTO (elas acabam sendo arbitrariamente longas)

  2. Os atributos da string devem ser armazenados como VARCHAR (o nome do usuário de destino, o assunto, etc ...).

Entendo que você tenha um limite de front-end, o que é ótimo até que não seja. * sorriso * O truque é pensar no banco de dados como separado dos aplicativos que se conectam a ele. Só porque um aplicativo coloca um limite nos dados, não significa que os dados sejam intrinsecamente limitados.

O que há nas próprias mensagens que as obriga a nunca ter mais de 3000 caracteres? Se for apenas uma restrição arbitrária de aplicativo (por exemplo, para uma caixa de texto ou algo assim), use um TEXTcampo na camada de dados.

James
fonte
O que significa "o que é ótimo até que não seja" significa? A que se refere "não"?
Pacerier
7
@Pacerier Para dar um exemplo do "não é", James provavelmente fala sobre: ​​Tomemos, por exemplo, o Twitter, que até muito recentemente tinha um limite de 140 caracteres para os PMs. Eles decidiram que não era mais sensato e optaram por remover esse limite completamente. Se eles não tivessem pensado sobre isso (o que tenho certeza de que provavelmente o fizeram ...), eles teriam se deparado com o cenário descrito acima.
PaulSkinner
9
Estou apenas criando nosso novo banco de dados, e eu supus que ninguém poderia colocar mais de 2000 caracteres em nossas minúsculas caixas de comentários e, como observa James, hoje à noite "de repente" não estava bem "porque um usuário passou por um comentário muito válido com 2600 caracteres. Eu usei varchar (2000) pensando que não poderia demorar mais do que isso, e eu estava errado. então sim, é ótimo até que não seja. No nosso caso, isso levou apenas alguns dias para se manifestar. A regra abaixo, Michael J. Calkins, acho que vou usar a partir de agora. texto para mensagens, comentários.
Lizardx
1
@Pacerier ", que é ótimo até que não seja ótimo". Em outras palavras, funciona quase o tempo todo e é maravilhoso ... exceto aquelas situações excepcionais em que não é tão bom.
Expiação limitada
@Pacerier Outro exemplo interessante é mencionado nos comentários da resposta selecionada, basicamente ele tinha um limite de front-end de 2.000 caracteres, mas os caracteres apresentados estavam em uma página de código que, na realidade, usava mais bytes do que letras normais, seu banco de dados acabou precisando de espaço para caracteres de 24k apenas porque ele teve que explicar o tamanho real de bytes dos caracteres que estão sendo introduzidos.
RaptorX 01/07/19
32

Isenção de responsabilidade: Eu não sou um especialista em MySQL ... mas esse é meu entendimento dos problemas.

Eu acho que o TEXT é armazenado fora da linha do mysql, enquanto eu acho que o VARCHAR é armazenado como parte da linha. Há um comprimento máximo de linha para linhas mysql. Portanto, você pode limitar a quantidade de outros dados que pode armazenar em uma linha usando o VARCHAR.

Também devido ao VARCHAR fazer parte da linha, eu suspeito que as consultas que olham para esse campo serão um pouco mais rápidas do que aquelas que usam um pedaço de texto.

Michael Anderson
fonte
38
O limite de comprimento da linha é de 65.535 bytes [ dev.mysql.com/doc/refman/5.0/en/column-count-limit.html ]. Se a sua coluna estiver codificada em utf8, isso significa que uma varcharcoluna de 3000 caracteres pode levar até 9000 bytes.
Jan Fabry
7
Os caracteres UTF-8 podem ter até 4 bytes, então acho que você quis dizer 12.000 bytes (a menos que haja alguma coisa do MySQL que eu não esteja entendendo aqui).
raylu
13
@raylu O UTF-8 do MySQL é "falso UTF-8", pois suporta apenas 3 bytes por caractere, portanto, não há como armazenar diretamente caracteres unicode além do plano BMP no UTF-8 do MySQL. Isso foi corrigido no MySQL 5.5.
Pacerier 06/07/12
2
Eu acredito que esta afirmação é válida apenas para o MyISAM. Não consigo encontrar uma fonte definitiva, mas acredito que o InnoDB também armazena TEXTinline na tabela.
dotancohen
2
@dotancohen I encontrada uma fonte aqui explicando que o armazenamento de dados de comprimento variável usando InnoDB pode variar (podem ser armazenados no exterior ou em linha dentro da fileira) mysqlserverteam.com/externally-stored-fields-in-innodb
KIX Ortillan
30

Resposta curta: Nenhuma diferença prática, de desempenho ou de armazenamento.

Resposta longa:

Não há essencialmente nenhuma diferença (no MySQL) entre VARCHAR(3000)(ou qualquer outro limite grande) e TEXT. O primeiro truncará em 3000 caracteres ; o último truncará em 65535 bytes . (Eu faço uma distinção entre bytes e caracteres porque um caractere pode levar vários bytes.)

Para limites menores VARCHAR, existem algumas vantagens TEXT.

  • "menor" significa 191, 255, 512, 767 ou 3072 etc., dependendo da versão, contexto e CHARACTER SET.
  • INDEXessão limitados em quão grande uma coluna pode ser indexada. (767 ou 3072 bytes ; isso depende da versão e das configurações)
  • Tabelas intermediárias criadas por complexos SELECTs são tratadas de duas maneiras diferentes - MEMORY (mais rápida) ou MyISAM (mais lenta). Quando colunas 'grandes' estão envolvidas, a técnica mais lenta é selecionada automaticamente. (Alterações significativas na versão 8.0; portanto, este item de marcador está sujeito a alterações.)
  • Relacionados ao item anterior, todos os TEXTtipos de dados (em oposição a VARCHAR) saltam diretamente para o MyISAM. Ou seja, TINYTEXTé automaticamente pior para as tabelas temporárias geradas do que o equivalente VARCHAR. (Mas isso leva a discussão em uma terceira direção!)
  • VARBINARYé como VARCHAR; BLOBé como TEXT.

Refutar outras respostas

A pergunta original fazia uma coisa (que tipo de dados usar); a resposta aceita respondeu outra coisa (armazenamento fora de registro). Essa resposta está desatualizada.

Quando esse encadeamento foi iniciado e respondido, havia apenas dois "formatos de linha" no InnoDB. Logo depois, mais dois formatos ( DYNAMICe COMPRESSED) foram introduzidos.

O local de armazenamento para TEXTe VARCHAR()é baseado no tamanho , não no nome do tipo de dados . Para uma discussão atualizada sobre armazenamento on / off-record de grandes colunas de texto / blob, consulte isso .

Rick James
fonte
1
Algumas boas idéias aqui. Essa deve ser a resposta aceita.
Kosta Kontos
2
@KostaKontos - Obrigado pelo elogio e pela correção de erros de digitação. Quando houver necessidade de uma resposta melhor, adicionarei uma resposta, mesmo que 8 anos e 800 votem tarde demais.
Rick James
7

As respostas anteriores não insistem o suficiente no problema principal: mesmo em consultas muito simples como

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

uma tabela temporária pode ser necessária e, se um VARCHARcampo estiver envolvido, ele será convertido em um CHARcampo na tabela temporária. Portanto, se você tiver em sua tabela digitado 500.000 linhas com um VARCHAR(65000)campo, somente esta coluna usará 6,5 * 5 * 10 ^ 9 bytes. Essas tabelas temporárias não podem ser tratadas na memória e são gravadas no disco. Pode-se esperar que o impacto seja catastrófico.

Origem (com métricas): https://nicj.net/mysql-text-vs-varchar-performance/ (refere-se à manipulação de TEXTvs VARCHARno mecanismo de armazenamento MyISAM "padrão" (?). Pode ser diferente em outros, por exemplo, InnoDB.)

Máx.
fonte
3
InnoDB: O mesmo se aplica à versão 5.7. Com 8.0, o varchar temps tem tamanho variável.
Rick James
3

Há uma enorme diferença entre VARCHAR e TEXT. Embora os campos VARCHAR possam ser indexados, os campos TEXT não podem. Os campos do tipo VARCHAR são armazenados em linha enquanto o TEXT é armazenado offline, apenas os ponteiros para os dados do TEXT são realmente armazenados nos registros.

Se você precisar indexar seu campo para pesquisar, atualizar ou excluir mais rapidamente do que o VARCHAR, não importa o tamanho. Um VARCHAR (10000000) nunca será o mesmo que um campo de TEXTO, pois esses dois tipos de dados são de natureza diferente.

  • Se você usar seu campo apenas para arquivamento
  • você não se importa com recuperação de velocidade de dados
  • você se preocupa com a velocidade, mas usará o operador '% LIKE%' em sua consulta de pesquisa para que a indexação não ajude muito
  • você não pode prever um limite do comprimento dos dados

do que ir para o texto.

Viktor Joras
fonte
Informações parcialmente enganosas: as colunas TEXT não podem ser indexadas por inteiro. Ao incluir uma coluna TEXTO no índice, você deve especificar o comprimento. Além disso, os VARCHARs não podem ser indexados em sua totalidade no caso de VARCHARs> 255, pois há um comprimento máximo no tamanho do índice.
eRadical
2

Varchar é para dados pequenos, como endereços de e-mail, enquanto Texto é para dados muito maiores, como artigos de notícias, e Blob, para dados binários, como imagens.

O desempenho do Varchar é mais poderoso porque ele roda completamente da memória, mas isso não será o caso se os dados forem muito grandes, como varchar(4000)por exemplo.

O texto, por outro lado, não adere à memória e é afetado pelo desempenho do disco, mas você pode evitar isso ao separar os dados de texto em uma tabela separada e aplicar uma consulta de junção esquerda para recuperar dados de texto.

O blob é muito mais lento; portanto, use-o apenas se você não tiver muitos dados, como 10000 imagens, que custarão 10000 registros.

Siga estas dicas para obter velocidade e desempenho máximos:

  1. Use varchar para nome, títulos, e-mails

  2. Use texto para dados grandes

  3. Separe o texto em tabelas diferentes

  4. Use as consultas de associação à esquerda em um ID, como um número de telefone

  5. Se você estiver usando o Blob, aplique as mesmas dicas de Texto

Isso fará com que as consultas custem milissegundos em tabelas com dados> 10 M e tamanho de até 10 GB garantidos.

Criativo87
fonte