Declarar VARCHAR
tamanho faz sentido para o desempenho? Existe alguma diferença (em velocidade) entre VARCHAR(50)
e VARCHAR(255)
? Ou definir comprimento é restrição lógica / de design?
mysql
database-design
Sonique
fonte
fonte
Respostas:
Essa é uma "pergunta de exame / entrevista" muito comum. Vou responder da melhor maneira possível:
Nos formatos de linha padrão para InnoDB e MyISAM (dinâmico / compacto), a
VARCHAR(50)
e aVARCHAR(255)
armazenam o texto da string da mesma maneira - 1 byte para o comprimento e a string real com entre 1 e 4 bytes por caractere (dependendo da codificação e o caractere real armazenado).De fato, se bem me lembro, lembro de alguém modificando o dicionário de dados com um editor hexadecimal para mudar algo como a
VARCHAR(50)
para aVARCHAR(100)
, para que isso pudesse ser feito dinamicamente (normalmente, isso requer uma reconstrução da tabela). E isso foi possível, porque os dados reais não foram afetados por essa alteração.Isso não é verdade
VARCHAR(256)
, pois sempre são necessários 2 bytes (pelo menos) para o comprimento.Então, isso significa que devemos sempre fazer
VARCHAR(255)
, não devemos? Não . Existem várias razões.Embora o InnoDB possa armazenar um varchar de maneira dinâmica, isso não é verdade para outros mecanismos. O MyISAM possui um formato de tamanho de linha fixo e as tabelas MEMORY são sempre de tamanho fixo. Devemos nos preocupar com esses outros motores? Sim, deveríamos, porque mesmo se não as usarmos diretamente, as tabelas MEMORY são muito usadas para resultados intermediários (tabelas temporárias na memória) e, como os resultados não são conhecidos antecipadamente, a tabela deve ser criada com o tamanho máximo possível -
VARCHAR(255)
se esse é o nosso tipo. Se você puder pensar no espaço desperdiçado, se estivermos usando a'utf8' charset
codificação do MySQL , MEMORY reservará 2 bytes para o comprimento + 3 * 255 bytes por linha(para valores que podem levar apenas alguns bytes no InnoDB). Isso é quase 1 GB em uma tabela de 1 milhão - apenas para o VARCHAR. Isso não apenas causa estresse desnecessário na memória, como também pode provocar as ações a serem executadas no disco, potencialmente diminuindo a velocidade milhares de vezes. Tudo isso devido a uma seleção ruim de seu tipo de dados definido (independentemente do conteúdo).Também tem algumas consequências para o InnoDB. O tamanho do índice é restrito a 3072 bytes e os índices de coluna única, a 767 bytes *. Portanto, é muito provável que você não consiga indexar completamente um
VARCHAR(255)
campo (supondo que você use utf8 ou qualquer outra variável de codificação de comprimento).Além disso, o tamanho máximo de linha embutida para o InnoDB é meia página (em torno de 8000 bytes) e os campos de comprimento variável, como BLOB ou varchar, podem ser armazenados fora da página se não caberem na meia página . Isso tem algumas consequências no desempenho (algumas vezes boas, outras ruins, dependendo do uso) que não podem ser ignoradas. Isso causou alguma estranheza entre os formatos COMPACT e DYNAMIC. Veja, por exemplo: erro 1118: tamanho da linha muito grande. utf8 innodb
Por último, mas não menos importante, como o @ypercube me lembrou, pode ser necessário mais de 1 byte para o comprimento, mesmo se você estiver usando
VARCHAR(255)
, porque a definição está em caracteres, enquanto o comprimento armazena bytes. Por exemplo,REPEAT('ñ', 255)
tem mais de 2 ^ 255 bytes em utf8, portanto, seria necessário mais de 1 byte para armazenar seu comprimento:Portanto, o conselho geral é usar o menor tipo possível , pois isso pode potencialmente criar problemas de desempenho ou gerenciamento. A
VARCHAR(100)
é melhor queVARCHAR(255)
(embora aVARCHAR(20)
seja melhor), mesmo que você não saiba o tamanho exato. Tente ser conservador porque, a menos que a tabela seja muito grande, você sempre poderá alterar a definição posteriormente.Atualização: como a popularidade explosiva de cadeias de comprimento variável, por exemplo, com o uso de emojis, a Oracle tem buscado melhorar o desempenho para esses casos. Nas versões mais recentes do MySQL (5.6, 5.7), o InnoDB foi definido como o mecanismo padrão para tabelas temporárias intrínsecas e explícitas, o que significa que os campos de comprimento variável são agora cidadãos de primeira classe. Isso significa que pode haver menos razões para ter comprimentos de caracteres muito restritos (mas eles ainda existem).
(*) Segunda atualização : large_prefix_index agora está habilitado por padrão nas versões mais recentes do MySQL (8.0), mas isso ainda é verdadeiro para versões mais antigas ou se você estiver usando formatos de arquivo / linha lagacy innodb (que não sejam dinâmicos ou compactados), mas agora por padrão, os índices de coluna única podem ter até esses 3072 bytes.
fonte
Esqueça o prefixo de 1 a 2 bytes ativado
VARCHARs
.A pergunta sobre 255 foi feita e respondida várias vezes.
VARCHARs
pode levar ao fracasso deCREATE TABLE
.MEMORY
tabelas, comVARCHARs
transformadas emVARCHAR
. Isso significa, por exemplo, queVARCHAR(255) CHARACTER SET utf8mb4
deseja um comprimento fixo de 1020 bytes. (Isso falhará e degenerará usando o MyISAM.)Conclusão: não use cegamente 255 (ou 256); faça o que faz sentido para o esquema.
fonte