Implicações de desempenho dos tamanhos MySQL VARCHAR

45

Existe uma diferença de desempenho no MySQL entre tamanhos de varchar? Por exemplo, varchar(25)e varchar(64000). Caso contrário, existe um motivo para não declarar todos os varchars com o tamanho máximo apenas para garantir que você não fique sem espaço?

BenV
fonte
3
+1 esta pergunta se aplica de maneira semelhante a todos os DBMS. Minha observação de muitos tamanhos de varchar tendem a crescer.
bernd_k
5
Não é MySQL, mas este post de Depesz pode responder à sua pergunta para o PostgreSQL .
Xenoterracide

Respostas:

29

Você deve perceber as vantagens e desvantagens de usar CHAR vs VARCHAR

Com os campos CHAR, o que você aloca é exatamente o que recebe. Por exemplo, CHAR (15) aloca e armazena 15 bytes, independentemente de como você coloca os caracteres no campo. A manipulação de strings é simples e direta, pois o tamanho do campo de dados é totalmente previsível.

Com os campos VARCHAR, você obtém uma história completamente diferente. Por exemplo, o VARCHAR (15) na verdade aloca dinamicamente até 16 bytes, até 15 para dados e, pelo menos, 1 byte adicional para armazenar o comprimento dos dados. Se você tiver a string 'hello' para armazenar que terá 6 bytes, não 5. A manipulação da string sempre deve executar alguma forma de verificação de comprimento em todos os casos.

A troca é mais evidente quando você faz duas coisas:
1. Armazenando milhões ou bilhões de linhas
2. Colunas de indexação que são CHAR ou VARCHAR

TRADEOFF # 1

Obviamente, o VARCHAR possui a vantagem, já que dados de comprimento variável produziriam linhas menores e, portanto, arquivos físicos menores.

TRADEOFF # 2

Como os campos CHAR requerem menos manipulação de sequência devido às larguras fixas, as pesquisas de índice no campo CHAR são, em média, 20% mais rápidas que as dos campos VARCHAR. Esta não é nenhuma conjectura da minha parte. O livro MySQL Database Design and Tuning executou algo maravilhoso em uma tabela MyISAM para provar isso. O exemplo no livro fez algo como o seguinte:

ALTER TABLE tblname ROW_FORMAT=FIXED;

Essa diretiva força os VARCHARs a se comportarem como CHARs. Eu fiz isso no meu trabalho anterior em 2007 e peguei uma tabela de 300 GB e acelerou as pesquisas de índice em 20%, sem alterar mais nada. Funcionou como publicado. No entanto, produziu uma tabela com quase o dobro de tamanho, mas isso simplesmente remonta ao tradeoff # 1.

Você pode analisar os dados que estão sendo armazenados para ver o que o MySQL recomenda para a definição de colunas. Basta executar o seguinte em qualquer tabela:

SELECT * FROM tblname PROCEDURE ANALYSE();

Isso percorrerá a tabela inteira e recomendará definições de coluna para todas as colunas com base nos dados que ela contém, nos valores mínimos de campo, no máximo e assim por diante. Às vezes, você só precisa usar o bom senso ao planejar CHAR vs VARCHAR. Aqui está um bom exemplo:

Se você estiver armazenando endereços IP, a máscara para essa coluna terá no máximo 15 caracteres (xxx.xxx.xxx.xxx). Eu pularia direto no CHAR (15) em um piscar de olhos, porque os comprimentos dos endereços IP não variariam muito e a complexidade adicional da manipulação de strings controlada por um byte adicional. Você ainda pode fazer uma ANÁLISE DE PROCEDIMENTO () nessa coluna. Pode até recomendar VARCHAR. Meu dinheiro ainda estaria em CHAR sobre VARCHAR nesse caso.

Os problemas CHAR x VARCHAR podem ser resolvidos apenas através do planejamento adequado. Com grande poder vem grande responsabilidade (clichê, mas é verdade)

RolandoMySQLDBA
fonte
4
Se você estiver armazenando endereços IP, não vejo motivo para armazená-los como algo diferente de um int. Isso é tudo o que é um endereço IP. Muitos idiomas têm algum tipo de função ip2int. Se quiser que o convienence de uma chamada de linha de comando não é difícil fazer um procedimento armazenado para converter ABCD: A pow (256,3) + b pow (256,2) + c * 256 + d
atxdba
1
Err mais para o ponto que eu acho mysql tem a sua função própria ip2int: INET_ATON
atxdba
3
@atxdba: O objetivo da minha resposta é apenas usar CHAR vs VARCHAR. Eu apenas uso o IP como exemplo, porque o tamanho do caractere da string é mais próximo de 15. Portanto, arredondar um tamanho estável do CHAR em favor do VARCHAR é apenas um exemplo para a própria pergunta. Seu comentário sobre melhores maneiras de representar endereços IP é bastante válido e faz mais sentido.
RolandoMySQLDBA
CHAR (15) aloca 15 caracteres , não bytes . Para utf8, são 45 bytes .
Rick James
2
Embora essa seja uma boa resposta sobre a comparação CHAR / VARCHAR, a pergunta era sobre diferentes tamanhos de VARCHAR.
Coletor
13

A resposta para isso é realmente bastante complexa. A versão curta: há uma diferença .

  1. Ao criar tabelas temporárias para filtrar resultados (por exemplo, GROUP BYinstruções), o comprimento total será alocado.

  2. O protocolo de conexão (enviando linhas para o cliente) provavelmente alocará o comprimento maior.

  3. O mecanismo de armazenamento pode / pode não implementar um varchar adequado.

Pois (2) admito que o protocolo de ligação não seja algo com o qual estou intimamente familiarizado, mas o conselho geral aqui é tentar aplicar pelo menos algum esforço mínimo para adivinhar o comprimento.

Morgan Tocker
fonte
Vale ressaltar. O MySQL 5.7 pode empacotar valores no buffer de classificação (comprimento variável). Explicado em mais detalhes aqui: mysqlserverteam.com/…
Morgan Tocker
9

A maioria das respostas neste tópico tem 5 anos, escritas antes do InnoDB e utf8 serem padrões. Então, deixe-me começar de novo ...

Quando uma consulta precisa de uma tabela temporária interna, ela tenta usar uma MEMORYtabela. Mas MEMORY não pode ser usado se

  • TEXT/ BLOBcolunas sendo buscadas, nem mesmo TINYTEXT.
  • VARCHAR maior que alguma quantia, provavelmente 512 na versão atual.

Além disso, observe que VARCHARssão transformados em CHARs. Portanto, VARCHAR(255)com um CHARACTER SET utf8expande para 765 bytes, independentemente do que está na coluna. Em seguida, isso pode ser acionado:

  • Se a MEMORYtabela ficar maior que um max_heap_table_size ou outro tmp_table_size, será convertida em MyISAM e potencialmente será derramada em disco.

Portanto, VARCHAR(25)é mais provável que fique MEMORY, portanto, seja mais rápido. (255)não é tão bom e (64000)é ruim.

(No futuro, as tabelas temporárias provavelmente serão InnoDB, e parte dessa resposta precisará ser revisada.)

Rick James
fonte
6

Uma coluna varchar desse tamanho aumenta a probabilidade de consultas em toda a tabela usarem tabelas temporárias. De acordo com o livro MySQL de alto desempenho. Quando o otimizador tenta ver se pode executar esta consulta na memória ou se precisa de uma tabela temporária, ele analisa o tamanho da linha com base na definição da tabela, ou seja, para velocidade, ele não tenta ver quanto dos caracteres de 64 K você está realmente usando. É por isso que os escritores recomendam que você não estique essa definição muito além dos possíveis valores reais que poderiam aparecer na coluna. Obviamente, se você se preparar para mais consultas em tabelas temporárias (mesmo que o tamanho real dos dados possa caber na RAM), você terá agora multas de E / S que poderia ter evitado.

TechieGurl
fonte
Essa é uma perspectiva muito nova. Se este é o livro ao qual você está se referindo ( amazon.com/MySQL-High-Availability-Building-Centers/dp/… ), coloque o número da página do livro em sua resposta, porque eu gostaria de ler isso. +1 !!!
RolandoMySQLDBA 19/10/11
Parvo-me… Alto desempenho não disponível: amazon.com/High-Performance-MySQL-Optimization-Replication/dp/…… o número da página é 236/237 Explica como a generosidade na definição de uma coluna varchar pode ser imprudente. Lembre-se, porém, de que este livro foi escrito quando o 5.1 foi lançado. A terceira edição está saindo no próximo ano para incluir todas as grandes mudanças em 5.5 talvez isso vai mudar :)
TechieGurl
Página 236 menciona agrupamento pertencente a conjuntos de caracteres específicos. Isso poderia ser meio desagradável para o VARCHAR. Na página 237, as configurações de comunicação cliente / servidor, juntamente com a Figura 5-5 na página 238, mostram outro motivo. O processo de tradução de caracteres se alterna. Novamente, outra aventura desagradável para o VARCHAR.
RolandoMySQLDBA
Para esclarecer, mesmo que esta seção não diga claramente que o MySQL utilizará o tamanho da criação, sabemos que quando uma operação precisa de uma tabela temporária, essa tabela está no MEMORY Engine e que sempre armazena tipos de string em fixos em pedaços, de modo que é generoso definição pode causar a tabela temporária de memória necessário para ir para o disco em vez de ficar na RAM
TechieGurl
@RolandoMySQLDBA. Sim ... isso também ... agrupamento também se torna um fator aqui (especialmente se você usa UTF-8 e possui caracteres não latinos) e tudo o mata quando se lida com uma tabela de mecanismo de memória e leva a uma viagem mais rápida ao disco
TechieGurl
5

Entendo que os campos menores podem ser incluídos diretamente no índice, enquanto os mais longos não podem. Devido a essa limitação, se você deseja que as strings sejam indexáveis, eu diria que as mantenha menores. Caso contrário, não, sendo assim, como ambos são varchar, as operações, como classificação ou comparação, funcionarão no mesmo tempo, independentemente de os campos serem 25 ou MAX.

jcolebrand
fonte
3

garantir que você não fique sem espaço

Essa frase implica que você faz a pergunta porque não tem certeza dos dados que estará armazenando no banco de dados. Se isso for verdade, você estará bem servido para descobrir o mais rápido possível, porque será necessário para o planejamento da capacidade. Se você pode obter elementos de dados com 7000 caracteres, por exemplo, é necessário saber porque isso teria implicações no desempenho de qualquer DBMS.

Dito isto, eu prefiro ter tamanhos de coluna relacionados ao conteúdo esperado. Por exemplo, é improvável que um número de telefone tenha mais de 50 caracteres, mesmo se você incluir um código e extensão de país. Da mesma forma, um CEP ou código postal provavelmente terá 20 caracteres ou menos.

Larry Coleman
fonte