Importância do comprimento varchar na tabela MySQL

112

Eu tenho uma tabela MySQL onde as linhas são inseridas dinamicamente. Como não posso ter certeza do comprimento das cordas e não as quero cortadas, faço-as varchar (200), que geralmente é muito maior do que preciso. Existe um grande impacto no desempenho em dar a um campo varchar muito mais comprimento do que o necessário?

Brian
fonte
Uma tabela com uma única VARCHAR(255) utf8mb4coluna indexada com aproximadamente 150 mil linhas mede 11,5 MB. Uma tabela com uma VARCHAR(48) utf8mb4coluna indexada com os mesmos dados (comprimento máximo de 46 caracteres) usou 4,5 MB. Não é realmente uma grande diferença nas consultas, é indexado. Mas adiciona E / S de consulta e coisas como backups de banco de dados.
Code4R7 de

Respostas:

59

Não, no sentido de que se os valores que você está armazenando nessa coluna são sempre (digamos) menos de 50 caracteres, declarando a coluna como varchar(50)ou varchar(200)tem o mesmo desempenho.

Alex Martelli
fonte
9
Não é exatamente verdade. Veja a resposta de Bill
Karwin
5
Acho que uma resposta como deve ser suportada por documentos, benchmarks ou algo semelhante.
Gokhan Sari
301

Há um possível impacto no desempenho: no MySQL, tabelas temporárias e MEMORYtabelas armazenam uma VARCHARcoluna como uma coluna de comprimento fixo, preenchida até seu comprimento máximo. Se você projetar VARCHARcolunas muito maiores do que o maior tamanho necessário, consumirá mais memória do que o necessário. Isso afeta a eficiência do cache, a velocidade de classificação, etc.

Bill Karwin
fonte
33
+1. Também descobri alguns drivers JDBC que alocam espaço suficiente para o tamanho máximo ao configurar buffers para recuperar linhas. Desnecessário dizer que isso causa muita angústia e ranger de dentes quando algum palhaço acaba de fazer varchar (50000), apenas no caso de alguém ter um sobrenome muito grande :-)
paxdiablo
21
+1. Esse é um impacto importante e acredito que essa seja a verdadeira resposta para essa pergunta.
Emre Yazici
6
Essa resposta e a resposta aceita são necessárias para entender a resposta correta ao OP.
kd8azz
2
Na verdade, quando tal MEMORYtabela é considerada muito grande, ela é gravada no disco, causando degradação significativa do desempenho.
Timo de
1
Essa resposta poderia ser relacionada à especificação de quais mecanismos de armazenamento ela é verdadeira (observo que dev.mysql.com/doc/refman/8.0/en/… indica que as tabelas temporárias são sempre InnoDB a partir do MySQL 8; isso muda alguma coisa?) , e com links para documentos que apoiam as afirmações que faz. Pelo que vi de sua saída no Stack Exchange, tenho fé que você estava certo quando escreveu isso, mas as coisas podem ter mudado, e os links seriam um bom exemplo para os outros e ajudariam a ensinar o resto de nós a encontrar este tipo de informação para nós mesmos.
Mark Amery
14

VARCHAR é ideal para a situação que você descreve, porque significa "caractere variável" - o limite, com base no seu exemplo, seria de 200 caracteres, mas qualquer coisa menos é aceita e não preencherá o tamanho atribuído da coluna.

VARCHAR também ocupa menos espaço - os valores são armazenados como um prefixo de comprimento de um ou dois bytes mais os dados. O prefixo de comprimento indica o número de bytes no valor. Uma coluna usa um byte de comprimento se os valores não exigirem mais de 255 bytes, e dois bytes de comprimento se os valores exigirem mais de 255 bytes.

Para obter mais informações comparando os tipos de dados MySQL CHAR e VARCHAR, consulte este link .

Pôneis OMG
fonte
1
todos os interessados ​​em armazenamento MySQL (sobre CHAR e VARCHAR) devem ler o link mencionado nesta resposta. Obrigado!
Pascal
14

Tamanho é desempenho! Quanto menor for o tamanho, melhor. Não hoje ou amanhã, mas algum dia suas mesas crescerão a um tamanho quando se trata de gargalos sérios, não importa o design que você definiu. Mas você pode prever alguns desses gargalos potenciais em sua fase de design que provavelmente ocorrerão primeiro e tentar expandir o tempo em que seu banco de dados terá um desempenho rápido e feliz até que você precise repensar seu esquema ou escalar horizontalmente adicionando mais servidores.

No seu caso, há muitos vazamentos de desempenho que você pode encontrar: grandes joins são quase impossíveis com varcharcolunas longas . A indexação nessas colunas é um verdadeiro assassino. Seu disco deve armazenar os dados. Uma página de memória pode conter menos linhas e as varreduras de tabela serão muito mais lentas. Além disso, o cache de consulta provavelmente não o ajudará aqui.

Você tem que se perguntar: Quantas inserções por ano podem acontecer? Qual é o comprimento médio? Eu realmente preciso de mais de 200 caracteres ou posso pegar isso no front-end do meu aplicativo, mesmo informando aos usuários sobre o comprimento máximo? Posso dividir a tabela em uma estreita para indexação e digitalização rápidas e outra para armazenar dados adicionais necessários com menos frequência de expansão de tamanho? Posso digitar os dados varchar possíveis em categorias e, assim, extrair alguns dos dados em algumas colunas menores, talvez int ou do tipo bool, e estreitar a coluna varchar dessa maneira?

Você pode fazer muito aqui. Pode ser melhor partir com uma primeira suposição e, em seguida, reprojetar passo a passo usando dados de desempenho medidos da vida real. Boa sorte.

Cutucar
fonte
+1 para listar opções de design e explorar o impacto. Muito útil para minha pergunta também. stackoverflow.com/q/12083089/181638
Assad Ebrahim
5
Existe algum impacto real no desempenho ao definir um comprimento máximo alto ou o desempenho é determinado apenas pelo tamanho real?
poolie de
5

Atuação? Não. Armazenamento em disco? Sim, mas é barato e abundante. A menos que seu banco de dados cresça para uma escala de terabytes, você provavelmente está bem.

duffymo
fonte
Estranho que esta resposta tenha sido rejeitada seis anos depois de ter sido postada e nenhuma das outras foi. Parece vingativo e mesquinho. Não há nada de incorreto nessa resposta. Moderadores?
duffymo
1
Como foi dito, isso afeta o desempenho. Além disso, o armazenamento em disco também não é gratuito. Uma coluna mais larga significa mais leituras / gravações no disco (e o acesso ao disco é lentoooooooo), e também índices mais amplos, o que reduz sua utilidade. Ambas as coisas afetam negativamente o desempenho. Talvez isso seja insignificante em um banco de dados pequeno, mas na escala gigabyte / terabyte com certeza fará diferença, como você diz. Para uma tabela de 100 registros, isso não importa.
Alejandro
5

Alguns de vocês estão enganados pensando que a varchar(200)ocupa mais tamanho de mesa no disco do que a varchar(20). Este não é o caso. Somente quando você vai além de 255 caracteres, o mysql usa um byte extra para determinar o comprimento dos varchardados do campo.

DCH
fonte
9
Não é assim para tabelas temporárias e MEMORYtabelas.
Lightness Races in Orbit
4
Sempre que sua consulta selecionada usar uma tabela temporária (agrupar e ordenar por operações, entre outras coisas), ela converterá varchar (200) em char (200) e o desempenho será prejudicado.
Jamie
1

Pode haver impactos de desempenho - mas geralmente não em um nível que a maioria dos usuários notaria.

Quando o tamanho de cada campo é conhecido com antecedência, o MySQL sabe exatamente quantos bytes estão entre cada campo / linha e pode avançar a página sem ler todos os dados. O uso de caracteres variáveis ​​diminui essa capacidade de otimização.

O varchar resulta em perda de desempenho devido à fragmentação de dados?

Melhor ainda, char vs varchar .

Para a maioria dos usos, você vai ficar bem com qualquer um - mas não é uma diferença, e para bancos de dados de grande escala, há razões por que você iria escolher um ou outro.

Rizwan Kassim
fonte
0

Sendo varchar, em vez de apenas char, o tamanho é baseado em um campo interno para indicar seu comprimento real e a própria string. Portanto, usar varchar (200) não é muito diferente de usar varchar (150), exceto que você tem o potencial de armazenar mais.

E você deve considerar o que acontece em uma atualização, quando uma linha cresce. Mas se isso for raro, então você deve estar bem.

Rob Farley
fonte
0

conforme o nome do tipo de dados sugere que este é VARCHAR, ou seja, armazenamento de dados de chars variáveis, o próprio mecanismo mysql aloca a memória que está sendo usada de acordo com os dados armazenados, portanto, não há impacto no desempenho de acordo com meu conhecimento.

user2903114
fonte
0

Você deve tentar visualizar uma coluna varchar da mesma forma que faria com uma coluna char na maioria dos cenários e definir o comprimento de forma conservadora. Você não precisa sempre pensar no modificador var tanto como algo que afeta sua tomada de decisão no comprimento máximo. Realmente deve ser visto como uma dica de desempenho, em vez de que as strings fornecidas serão de comprimentos variados.

Não é uma diretiva que deva ser estritamente seguida pela parte interna do banco de dados, ela pode ser completamente ignorada. No entanto, tome cuidado com isso, pois às vezes a implementação pode vazar (comprimento e preenchimento fixos, por exemplo), embora não devesse em um mundo ideal.

Se você tiver um varchar (255), não terá garantia de que, em termos de desempenho, ele sempre se comportará de maneira diferente de um char (255) em todas as circunstâncias.

Pode parecer fácil configurá-lo em algo como 255, 65535, etc. em linha com o conselho dado no manual sobre requisitos de armazenamento. Isso dá a impressão de que qualquer valor entre 0 (sim, é uma coisa) e 255 terá o mesmo impacto. No entanto, isso não é algo que pode ser totalmente garantido.

Os requisitos de armazenamento tendem a ser verdadeiros ou um bom indicador para mecanismos de armazenamento persistente decentes e maduros em termos de armazenamento em linha. Não é um indicador tão forte para coisas como índices.

Às vezes é uma questão difícil, exatamente quanto comprimento um pedaço de corda deve ter, então configurando-o no limite mais alto que você sabe que deve estar, mas isso não tem impacto. Infelizmente, isso geralmente é algo deixado para o usuário resolver e é realmente um tanto arbitrário. Você realmente não pode dizer nunca ultrapasse o tamanho de uma string, porque talvez haja casos em que você não tem certeza.

Você deve garantir que as consultas do MySQL gerem um erro quando uma string for muito longa, em vez de truncada, para que pelo menos você saiba se ela pode ser muito curta devido à emissão de erros. Redimensionar colunas para aumentá-las ou reduzi-las pode ser uma operação DDL cara, isso deve ser mantido em mente.

O conjunto de caracteres também deve ser considerado onde a duração e o desempenho entram em jogo. O comprimento se refere a isso em vez de bytes. Se usar utf8, por exemplo, (não MB4), então varchar (255) é realmente varbinary (3 * 255). É difícil saber como coisas como essa vão realmente funcionar sem executar testes e examinar profundamente o código-fonte / documentação. Por causa disso, é possível que comprimento excessivo tenha um impacto inesperadamente inflado. isso não se aplica apenas ao desempenho. Se um dia você precisar alterar o conjunto de caracteres de uma coluna varchar para uma coluna maior, você pode acabar atingindo algum limite sem recurso, se permitir a presença de cadeias de caracteres excessivamente longas que poderiam ter sido evitadas. Este é normalmente um problema de nicho, mas surge,

Se for descoberto que MAX (LENGTH (coluna)) é sempre <64 (como se fosse decidido que haveria um limite de entrada que não correspondia à definição da coluna), mas você tem varchar (255), então há um boa chance de você usar quatro vezes mais espaço do que o necessário em alguns cenários.

Isso pode incluir:

  • Motores diferentes, alguns podem ignorá-lo completamente.
  • Tamanhos de buffer, por exemplo, atualizar ou inserir podem ter que alocar o 255 completo (embora eu não tenha verificado o código-fonte para provar isso, é apenas uma hipótese).
  • Índices, isso será imediatamente óbvio se você tentar fazer uma chave composta de várias colunas varchar (255).
  • Tabelas intermediárias e possivelmente conjuntos de resultados. Dada a maneira como as transações funcionam, pode nem sempre ser possível que algo use o comprimento máximo real das strings em uma coluna, em oposição ao limite definido.
  • Otimizações preditivas internas podem usar o comprimento máximo como uma entrada.
  • Mudanças nas versões de implementação do banco de dados.

Como regra geral, não há realmente necessidade de um varchar ser mais longo do que o necessário, com problemas de desempenho ou não, então eu recomendo que continue assim quando puder. Fazer mais esforço para amostrar o tamanho de seus dados, impor um limite verdadeiro ou descobrir o limite verdadeiro perguntando / pesquisando é a abordagem ideal.

Quando você não puder, se quiser fazer algo como varchar (255) para casos de dúvida, eu recomendo fazer a ciência. Isso pode consistir em duplicar a tabela, reduzir o tamanho da coluna var char, em seguida, copiar os dados do original e olhar para o tamanho dos dados de índice / linha (indexar a coluna também, também tentar como uma chave primária que pode se comportar de maneira diferente no InnoDB já que as linhas são ordenadas por chave primária). No mínimo, dessa forma você saberá se tem um impacto no IO que tende a ser um dos gargalos mais sensíveis. Testar o uso de memória é mais difícil, é difícil testar exaustivamente. Eu recomendaria testar os piores casos potenciais (consultas com muitos resultados intermediários na memória, verificar com explain para grandes tabelas temporárias, etc).

Se você sabe que não haverá muitas linhas na tabela, não usará a coluna para junções, índices (especialmente compostos, únicos), etc, então provavelmente não terá muitos problemas.

jgmjgm
fonte