Todo mundo sabe que, em tabelas que usam o InnoDB como mecanismo, consultas como SELECT COUNT(*) FROM mytable
são muito inexatas e muito lentas, especialmente quando a tabela fica maior e há inserções / exclusões constantes de linhas enquanto essa consulta é executada.
Pelo que entendi, o InnoDB não armazena a contagem de linhas em uma variável interna, que é a razão desse problema.
Minha pergunta é: por que isso acontece? Seria tão difícil armazenar essas informações? É uma informação importante para saber em tantas situações. A única dificuldade que vejo se uma contagem interna seria implementada é quando as transações estão envolvidas: se a transação não for confirmada, você conta as linhas inseridas por ela ou não?
PS: Eu não sou especialista em DBs, sou apenas alguém que tem o MySQL como um hobby simples. Portanto, se eu apenas pedir algo estúpido, não seja excessivamente crítico: D.
SELECT COUNT(*) FROM ...
consultas reais são precisas. Se preferir, o phpMyAdmin pode ser configurado para sempre usar contagens exatas de linhas à custa da velocidade. Mais informações: stackoverflow.com/questions/11926259/...Respostas:
Concordo com @RemusRusanu (+1 para sua resposta)
SELECT COUNT(*) FROM mydb.mytable
no InnoDB se comporta como um mecanismo de armazenamento transacional deveria. Compare com o MyISAM.MyISAM
Se
mydb.mytable
for uma tabela MyISAM, iniciarSELECT COUNT(*) FROM mydb.mytable;
é como executarSELECT table_rows FROM information_schema.table WHERE table_schema = 'mydb' AND table_name = 'mytable';
. Isso aciona uma pesquisa rápida da contagem de linhas no cabeçalho da tabela MyISAM.InnoDB
Se
mydb.mytable
for uma tabela do InnoDB, você terá uma mistura de coisas acontecendo. Você tem o MVCC em andamento, governando o seguinte:Pedir uma contagem de tabelas ao InnoDB requer navegação por essas coisas ameaçadoras. De fato, nunca se sabe realmente se
SELECT COUNT(*) from mydb.mytable
conta apenas leituras repetíveis ou inclui leituras que foram confirmadas e não confirmadas.Você pode tentar estabilizar um pouco as coisas ativando innodb_stats_on_metadata .
De acordo com a documentação do MySQL em innodb_stats_on_meta_data
Desativá-lo pode ou não fornecer uma contagem mais estável em termos de configuração de planos EXPLAIN. Isso pode afetar o desempenho de
SELECT COUNT(*) from mydb.mytable
uma maneira boa, ruim ou de maneira alguma. Experimente e veja !!!fonte
Para iniciantes, não existe a "contagem atual" para armazenar em uma variável. Uma consulta como
SELECT COUNT(*) FROM ...
está sujeita ao nível de isolamento atual e a todas as transações pendentes simultâneas. Dependendo do nível de isolamento, a consulta pode ver ou não ver linhas inseridas ou excluídas por transações não confirmadas pendentes. A única maneira de responder é contar as linhas que são visíveis para a transação atual.Observe que eu nem toquei no assunto ainda mais espinhoso das transações simultâneas que começam ou terminam durante a contagem. Sem mencionar reversões ...
fonte
COUNT(*)
consultas raramente são necessárias na realidade e geralmente resultam de inexperiência do desenvolvedor (conte as linhas antes de selecioná-las!) Ou de um design de aplicativo ruim.SELECT COUNT(*)
, adicione um não otimizadoWHERE
à tabela e você terá alguns usuários trazendo o db de joelhos para vários contadores de estatísticas úteis.Embora teoricamente fosse possível manter uma contagem precisa do número de linhas para uma determinada tabela com o InnoDB, isso custaria muito bloqueio, o que afetaria negativamente o desempenho. Também diferiria com base no nível de isolamento.
O MyISAM já faz o bloqueio no nível da tabela, portanto não há custo extra.
Raramente preciso de uma contagem de linhas para uma tabela, embora use COUNT (*) um pouco. Geralmente, tenho uma cláusula WHERE anexada. Usando um índice eficiente em um pequeno conjunto de resultados, acho que eles são rápidos o suficiente.
Não concordo que as contagens sejam imprecisas. As contagens representam um instantâneo dos dados, e eu sempre os achei exatos.
Em resumo, o MySQL deixa você implementar isso para o InnoDB. Você pode armazenar uma contagem e incrementá-la / diminuí-la após cada consulta. Porém, a solução mais fácil é provavelmente mudar para o MyISAM.
fonte