Existe uma diferença de desempenho mensurável entre o uso do INT e do VARCHAR como chave primária no MySQL? Eu gostaria de usar o VARCHAR como a chave primária para listas de referência (pense nos Estados Unidos, códigos de país) e um colega de trabalho não se moverá no INT AUTO_INCREMENT como chave primária para todas as tabelas.
Meu argumento, conforme detalhado aqui , é que a diferença de desempenho entre INT e VARCHAR é insignificante, uma vez que toda referência de chave estrangeira INT exigirá que um JOIN compreenda a referência, uma chave VARCHAR apresentará diretamente as informações.
Então, alguém tem experiência com esse caso de uso específico e as preocupações de desempenho associadas a ele?
mysql
performance
primary-key
innodb
myisam
Jake McGraw
fonte
fonte
Respostas:
Você deve enfatizar que pode evitar um certo número de consultas unidas usando o que é chamado de chave natural em vez de uma chave substituta . Somente você pode avaliar se o benefício disso é significativo em seu aplicativo.
Ou seja, você pode medir as consultas em seu aplicativo que são as mais importantes a serem rápidas, porque elas trabalham com grandes volumes de dados ou são executadas com muita frequência. Se essas consultas se beneficiarem da eliminação de uma associação e não sofrerem o uso de uma chave primária varchar, faça-o.
Não use nenhuma das estratégias para todas as tabelas no seu banco de dados. É provável que, em alguns casos, uma chave natural seja melhor, mas em outros casos uma chave substituta seja melhor.
Outras pessoas afirmam que é raro na prática uma chave natural nunca mudar ou ter duplicatas; portanto, chaves substitutas geralmente valem a pena.
fonte
Não é sobre desempenho. É sobre o que faz uma boa chave primária. Único e imutável ao longo do tempo. Você pode pensar que uma entidade como um código de país nunca muda ao longo do tempo e seria um bom candidato a uma chave primária. Mas a experiência amarga é que raramente é assim.
INT AUTO_INCREMENT atende à condição "única e imutável ao longo do tempo". Daí a preferência.
fonte
Fiquei um pouco irritado com a falta de referências para este online, então eu mesmo fiz um teste.
Observe, porém, que eu não faço isso regularmente, portanto, verifique minhas configurações e etapas quanto a fatores que possam ter influenciado os resultados sem querer e publique suas preocupações nos comentários.
A configuração foi a seguinte:
As mesas:
Em seguida, preenchi 10 milhões de linhas em cada tabela com um script PHP cuja essência é assim:
Para
int
tabelas, o bit($keys[rand(0, 9)])
foi substituído por justrand(0, 9)
e, paravarchar
tabelas, usei nomes completos de estados dos EUA, sem cortá-los ou estendê-los para 6 caracteres.generate_random_string()
gera uma sequência aleatória de 10 caracteres.Então eu corri no MySQL:
SET SESSION query_cache_type=0;
jan_int
tabela:SELECT count(*) FROM jan_int WHERE myindex = 5;
SELECT BENCHMARK(1000000000, (SELECT count(*) FROM jan_int WHERE myindex = 5));
myindex = 'califo'
parachar
tabelas emyindex = 'california'
paravarchar
tabelas.Tempos da
BENCHMARK
consulta em cada tabela:Em relação aos tamanhos de tabela e índice, eis a saída de
show table status from janperformancetest;
(com algumas colunas não mostradas):Minha conclusão é que não há diferença de desempenho para este caso de uso específico.
fonte
INDEX
vez dePRIMARY KEY
. Não me lembro do meu raciocínio - provavelmente presumi quePRIMARY KEY
é apenas umaINDEX
restrição com exclusividade. No entanto, lendo a seção sobre como as coisas são armazenadas no InnoDB em federico-razzoli.com/primary-key-in-innodb , acho que meus resultados ainda se aplicam às chaves primárias e respondem à pergunta sobre a diferença de desempenho da pesquisa de valor. Além disso, seu comentário sugere analisar o desempenho dos algoritmos de classificação , que não se aplicam ao caso de uso que investigo, que está pesquisando valores em um conjunto.Depende do comprimento. Se o varchar tiver 20 caracteres e o int for 4, se você usar um int, seu índice terá CINCO vezes mais nós por página do espaço do índice no disco ... Isso significa que o deslocamento o índice exigirá um quinto do número de leituras físicas e / ou lógicas.
Portanto, se o desempenho for um problema, dada a oportunidade, sempre use uma chave integral não significativa (chamada substituta) para suas tabelas e para Chaves estrangeiras que fazem referência às linhas nessas tabelas ...
Ao mesmo tempo , para garantir a consistência dos dados, todas as tabelas importantes também devem ter uma chave alternativa não numérica significativa (ou índice exclusivo) para garantir que linhas duplicadas não possam ser inseridas (duplicadas com base em atributos significativos da tabela).
Para o uso específico que você está falando (como pesquisas de estado), isso realmente não importa, porque o tamanho da tabela é muito pequeno. Em geral, não há impacto no desempenho dos índices em tabelas com menos de alguns milhares de linhas. ..
fonte
Absolutamente não.
Eu fiz várias ... várias ... verificações de desempenho entre INT, VARCHAR e CHAR.
A tabela de 10 milhões de registros com uma PRIMARY KEY (exclusiva e agrupada) teve exatamente a mesma velocidade e desempenho (e custo de subárvore), independentemente de qual dos três eu usei.
Dito isto ... use o que for melhor para sua aplicação. Não se preocupe com o desempenho.
fonte
Para códigos curtos, provavelmente não há diferença. Isso é especialmente verdade, pois a tabela que contém esses códigos provavelmente é muito pequena (no máximo duas mil linhas) e não muda com frequência (quando é a última vez que adicionamos um novo estado dos EUA).
Para tabelas maiores com uma variação maior entre as teclas, isso pode ser perigoso. Pense em usar o endereço de email / nome de usuário de uma tabela Usuário, por exemplo. O que acontece quando você tem alguns milhões de usuários e alguns desses usuários têm nomes longos ou endereços de email. Agora, sempre que você precisar ingressar nesta tabela usando essa chave, ela se tornará muito mais cara.
fonte
Quanto à Chave Primária, o que quer que torne fisicamente uma linha exclusiva deve ser determinado como a chave primária.
Para uma referência como chave estrangeira, o uso de um número inteiro com auto incremento como substituto é uma boa idéia por dois motivos principais.
- Primeiro, geralmente há menos despesas gerais na associação.
- Segundo, se você precisar atualizar a tabela que contém o varchar exclusivo, a atualização deverá cascatear para todas as tabelas filho e atualizar todas elas e também os índices, enquanto que com o substituto int, ele somente precisará atualizar o tabela mestre e seus índices.
A desvantagem de usar o substituto é que você poderia permitir a alteração do significado do substituto:
Tudo depende do que você realmente precisa se preocupar em sua estrutura e do que significa mais.
fonte
Casos comuns em que um substituto
AUTO_INCREMENT
dói:Um padrão de esquema comum é um mapeamento de muitos para muitos :
O desempenho desse padrão é muito melhor, especialmente ao usar o InnoDB:
Por quê?
id
um índice.Outro caso ( país ):
Com muita frequência, o iniciante normaliza o código do país em 4 bytes em
INT
vez de usar uma sequência de caracteres 'natural' de 2 bytes e quase inalterada. Mais rápido, menor, menos JOINs, mais legível.fonte
No HauteLook, alteramos muitas de nossas tabelas para usar chaves naturais. Tivemos um aumento no desempenho no mundo real. Como você mencionou, muitas de nossas consultas agora usam menos junções, o que torna as consultas com melhor desempenho. Até usaremos uma chave primária composta, se fizer sentido. Dito isto, algumas tabelas são mais fáceis de trabalhar se tiverem uma chave substituta.
Além disso, se você estiver permitindo que as pessoas gravem interfaces em seu banco de dados, uma chave substituta pode ser útil. A terceira parte pode confiar no fato de que a chave substituta será alterada apenas em circunstâncias muito raras.
fonte
Eu enfrentei o mesmo dilema. Fiz um DW (esquema de constelação) com 3 tabelas de fatos, acidentes rodoviários, veículos em acidentes e baixas em acidentes. Os dados incluem todos os acidentes registrados no Reino Unido de 1979 a 2012 e 60 tabelas de dimensões. Ao todo, cerca de 20 milhões de registros.
Relacionamentos de tabelas de fatos:
RDMS: MySQL 5.6
Nativamente, o índice de acidentes é um varchar (números e letras), com 15 dígitos. Tentei não ter chaves substitutas, pois os índices de acidentes nunca mudavam. Em um computador i7 (8 núcleos), o DW ficou muito lento para consultar após 12 milhões de registros de carga, dependendo das dimensões. Depois de muito trabalho e adicionando chaves substitutas bigint, obtive um aumento médio de 20% na velocidade. Ainda com baixo ganho de desempenho, mas tentativa válida. Estou trabalhando no ajuste e cluster do MySQL.
fonte
A questão é sobre o MySQL, então eu digo que há uma diferença significativa. Se fosse sobre o Oracle (que armazena números como string - sim, eu não podia acreditar no começo), então não havia muita diferença.
O armazenamento na tabela não é o problema, mas é a atualização e a referência ao índice. As consultas que envolvem a pesquisa de um registro com base em sua chave primária são frequentes - você deseja que ocorram o mais rápido possível, porque ocorre com muita frequência.
O problema é que uma CPU lida com números inteiros de 4 e 8 bytes naturalmente, em silício . É REALMENTE rápido comparar dois números inteiros - isso acontece em um ou dois ciclos de clock.
Agora observe uma sequência - ela é composta por muitos caracteres (mais de um byte por caractere hoje em dia). A comparação de duas strings para precedência não pode ser feita em um ou dois ciclos. Em vez disso, os caracteres das strings devem ser iterados até que seja encontrada uma diferença. Tenho certeza de que existem truques para torná-lo mais rápido em alguns bancos de dados, mas isso é irrelevante aqui porque uma comparação int é feita naturalmente e extremamente rápida em silício pela CPU.
Minha regra geral - toda chave primária deve ser uma INT autoincrementante, especialmente em aplicativos OO usando um ORM (Hibernate, Datanucleus, qualquer que seja) onde haja muitos relacionamentos entre objetos - eles geralmente sempre são implementados como um FK simples e a capacidade de O banco de dados para resolvê-los rapidamente é importante para a capacidade de resposta do seu aplicativo.
fonte
Não tenho certeza sobre as implicações de desempenho, mas parece que um possível comprometimento, pelo menos durante o desenvolvimento, seria incluir tanto a chave "substituta" inteira auto-incrementada como a chave pretendida, única e "natural". Isso daria a você a oportunidade de avaliar o desempenho, bem como outros possíveis problemas, incluindo a mutabilidade das chaves naturais.
fonte
Como sempre, não há respostas gerais. 'Depende!' e eu não estou sendo ridículo. Meu entendimento da pergunta original era que as chaves em pequenas tabelas - como Country (código inteiro ou código char / varchar) - eram uma chave estrangeira para uma tabela potencialmente enorme, como endereço / tabela de contatos.
Existem dois cenários aqui quando você deseja retornar os dados do banco de dados. Primeiro, é um tipo de consulta de lista / pesquisa em que você deseja listar todos os contatos com códigos ou nomes de estados e países (os IDs não ajudarão e, portanto, precisarão de uma pesquisa). O outro é um cenário de obtenção na chave primária, que mostra um único registro de contato em que o nome do estado, país precisa ser mostrado.
Para o último, provavelmente não importa em que o FK se baseia, pois estamos reunindo tabelas para um único registro ou alguns registros e leituras de teclas. O cenário anterior (pesquisa ou lista) pode ser afetado por nossa escolha. Como é necessário mostrar o país (pelo menos um código reconhecível e talvez até a pesquisa em si inclua um código do país), não é possível ter que ingressar em outra tabela por meio de uma chave substituta (apenas estou sendo cauteloso aqui porque não testei realmente isso, mas parece altamente provável) melhorar o desempenho; apesar do fato de que certamente ajuda na pesquisa.
Como os códigos são pequenos em tamanho - não mais que três caracteres geralmente para país e estado, pode ser bom usar as chaves naturais como chaves estrangeiras nesse cenário.
O outro cenário em que as chaves dependem de valores mais variáveis do varchar e talvez de tabelas maiores; a chave substituta provavelmente tem a vantagem.
fonte
Permita-me dizer que sim, definitivamente há uma diferença, levando em consideração o escopo do desempenho (definição pronta para uso):
1- O uso de substituto int é mais rápido no aplicativo porque você não precisa usar ToUpper (), ToLower (), ToUpperInvarient () ou ToLowerInvarient () no seu código ou na sua consulta e essas 4 funções têm diferentes parâmetros de desempenho. Veja as regras de desempenho da Microsoft sobre isso. (desempenho da aplicação)
2- O uso de substituto int garante não alterar a chave ao longo do tempo. Até os códigos dos países podem mudar, consulte a Wikipedia como os códigos ISO foram alterados ao longo do tempo. Isso levaria muito tempo para alterar a chave primária das subárvores. (desempenho da manutenção de dados)
3- Parece que existem problemas com as soluções ORM, como o NHibernate quando PK / FK não é int. (desempenho do desenvolvedor)
fonte