Encontrei artigos que afirmam que SELECT COUNT(*) FROM TABLE_NAME
serão lentos quando a tabela tiver muitas linhas e muitas colunas.
Eu tenho uma tabela que pode conter até bilhões de linhas [tem aproximadamente 15 colunas]. Existe uma maneira melhor de obter a contagem EXATA do número de linhas de uma tabela?
Considere o seguinte antes da sua resposta:
Estou procurando uma solução independente de fornecedor de banco de dados. Tudo bem se ele cobre MySQL , Oracle , MS SQL Server . Mas se realmente não houver uma solução independente de fornecedor de banco de dados, decidirei por soluções diferentes para diferentes fornecedores de banco de dados.
Não posso usar nenhuma outra ferramenta externa para fazer isso. Estou procurando principalmente uma solução baseada em SQL.
Não posso normalizar mais o design do meu banco de dados. Já está no 3NF e, além disso, muitos códigos já foram escritos em torno dele.
Respostas:
Resposta simples:
COUNT(*)
Notas:
COUNT (1) = COUNT (*) = COUNT (PrimaryKey) apenas no caso
Editar:
Exemplo do SQL Server (1,4 bilhões de linhas, 12 colunas)
1 execuções, 5:46 minutos, contagem = 1.401.659.700
2 execuções, ambas com menos de 1 segundo, contagem = 1.401.659.670
O segundo tem menos linhas = errado. Seria o mesmo ou mais, dependendo das gravações (as exclusões são feitas fora de horas aqui)
fonte
COUNT(*) = COUNT(key)
. Isso está errado. Se não houverNOT NULL
restrição - eles não poderão ser iguais (nos resultados e no plano de execução).index_id < 2
?A maneira mais rápida de longe no MySQL é:
Você receberá instantaneamente todas as suas tabelas com a contagem de linhas (que é o total), juntamente com muitas informações extras, se desejar.
fonte
Isso depende do banco de dados. Algumas aceleram a contagem, por exemplo, controlando se as linhas estão ativas ou não no índice, permitindo uma varredura de índice apenas para extrair o número de linhas. Outros não, e consequentemente exigem visitar a tabela inteira e contar linhas dinâmicas uma a uma. Ou será lento para uma mesa enorme.
Observe que geralmente você pode extrair uma boa estimativa usando ferramentas de otimização de consulta, estatísticas de tabela, etc. No caso do PostgreSQL, por exemplo, você pode analisar a saída
explain count(*) from yourtable
e obter uma estimativa razoavelmente boa do número de linhas. O que me leva à sua segunda pergunta.Seriamente? :-) Você realmente quer dizer a contagem exata de uma tabela com bilhões de linhas? Tens mesmo a certeza? :-)
Se você realmente fizer isso, poderá manter um rastreamento do total usando gatilhos, mas lembre-se da simultaneidade e dos impasses.
fonte
Para responder sua pergunta simplesmente, não .
Se você precisar de uma maneira independente de DBMS de fazer isso, a maneira mais rápida será sempre:
Alguns fornecedores de DBMS podem ter maneiras mais rápidas de funcionar apenas para seus sistemas. Algumas dessas opções já foram publicadas em outras respostas.
COUNT(*)
deve ser otimizado pelo DBMS (pelo menos qualquer banco de dados com valor de PROD) de qualquer maneira, portanto, não tente ignorar as otimizações.Em uma nota lateral:
Tenho certeza de que muitas de suas outras consultas também levam muito tempo para serem concluídas devido ao tamanho da sua tabela. Provavelmente, qualquer preocupação com o desempenho deve ser resolvida pensando no design do seu esquema tendo em mente a velocidade. Sei que você disse que não é uma opção de alteração, mas pode acontecer que consultas com mais de 10 minutos também não sejam uma opção. A 3ª NF nem sempre é a melhor abordagem quando você precisa de velocidade e, às vezes, os dados podem ser particionados em várias tabelas se os registros não precisarem ser armazenados juntos. Algo para pensar sobre...
fonte
Eu recebi esse script de outra pergunta / resposta do StackOverflow:
Minha tabela possui 500 milhões de registros e os retornos acima em menos de 1 ms. Entretanto,
leva 39 minutos, 52 segundos!
Eles produzem exatamente o mesmo número de linhas (no meu caso, exatamente 519326012).
Não sei se esse sempre seria o caso.
fonte
Você pode tentar este sp_spaceused (Transact-SQL)
fonte
Se a edição do SQL Server for 2005/2008, você poderá usar as DMVs para calcular a contagem de linhas em uma tabela:
Para o mecanismo de banco de dados do SQL Server 2000, os sysindexes funcionarão, mas é altamente recomendável evitar usá-lo em edições futuras do SQL Server, pois ele pode ser removido no futuro próximo.
Código de exemplo extraído de: Como obter contagens de linhas da tabela de maneira rápida e indolor
fonte
eu uso
fonte
Não sou tão experiente quanto os outros que responderam, mas estava tendo um problema com um procedimento que estava usando para selecionar uma linha aleatória de uma tabela (não muito relevante), mas precisava saber o número de linhas na minha tabela de referência para calcular o índice aleatório. Usando o trabalho tradicional Count (*) ou Count (1), eu ocasionalmente levava 2 segundos para executar minha consulta. Então, em vez disso (para minha tabela chamada 'tbl_HighOrder'), estou usando:
Funciona muito bem e os tempos de consulta no Management Studio são zero.
fonte
Bem, atrasado 5 anos e não tenho certeza se isso ajuda:
Eu estava tentando contar o não. de linhas em uma tabela do SQL Server usando o MS SQL Server Management Studio e ocorreu algum erro de estouro, então usei o abaixo:
selecione count_big (1) FROM [dbname]. [dbo]. [FactSampleValue];
O resultado :
24296650578 linhas
fonte
Encontrei este bom artigo SQL Server – HOW-TO: recupere rapidamente a contagem precisa de linhas da tabela, a partir da
martijnh1
qual é possível recapitular cada cenário.Preciso que isso seja expandido, onde forneça uma contagem com base em uma condição específica e, quando descobrir esta parte, atualizarei mais essa resposta.
Enquanto isso, aqui estão os detalhes do artigo:
Método 1:
Inquerir:
Comentários:
Executa uma verificação completa da tabela. Lento em mesas grandes.
Método 2:
Inquerir:
Comentários:
Maneira rápida de recuperar a contagem de linhas. Depende das estatísticas e é impreciso.
Execute DBCC UPDATEUSAGE (banco de dados) WITH COUNT_ROWS, que pode levar um tempo significativo para tabelas grandes.
Método 3:
Inquerir:
Comentários:
A maneira como o SQL Management Studio conta linhas (veja as propriedades da tabela, armazenamento, contagem de linhas). Muito rápido, mas ainda assim um número aproximado de linhas.
Método 4:
Inquerir:
Comentários:
Operação rápida (embora não tão rápida quanto o método 2) e igualmente importante, confiável.
fonte
Eu não acho que exista uma solução geral sempre mais rápida: algumas versões do RDBMS / têm uma otimização específica para
SELECT COUNT(*)
usar opções mais rápidas, enquanto outras simplesmente fazem a varredura de tabela. Você precisaria ir aos sites de documentação / suporte para o segundo conjunto, que provavelmente precisará de alguma consulta mais específica para ser escrita, geralmente uma que atinja um índice de alguma forma.EDITAR:
Aqui está um pensamento que pode funcionar, dependendo do seu esquema e distribuição dos dados: você tem uma coluna indexada que faz referência a um valor crescente, um ID numérico crescente, por exemplo, ou mesmo um carimbo de data / hora? Então, supondo que as exclusões não ocorram, deve ser possível armazenar a contagem até algum valor recente (data de ontem, valor mais alto de ID em algum ponto recente da amostra) e adicionar a contagem além disso, o que deve ser resolvido muito rapidamente no índice . Muito dependente de valores e índices, é claro, mas aplicável a praticamente qualquer versão de qualquer DBMS.
fonte
SELECT COUNT(*)
. Até o MySQL aparentemente faz isso.Estou atrasado para esta pergunta, mas aqui está o que você pode fazer com o MySQL (como eu uso o MySQL). Estou compartilhando minhas observações aqui:
Resultado
Contagem de linhas: 508534
Saída do console: linhas afetadas: 0 linhas encontradas: 1 avisos: 0 duração para 1 consulta: 0.125 seg.
Demora um tempo para uma tabela com grande número de linhas, mas a contagem de linhas é muito exata.
Resultado
Contagem de linhas: 511235
Saída do console : Linhas afetadas: 0 Linhas encontradas: 1 Avisos: 0 Duração para 1 consulta: 0,250 s Resumo: A contagem de linhas não é exata.
Resultado
Contagem de linhas: 507806
Saída do console : Linhas afetadas: 0 Linhas encontradas: 48 Avisos: 0 Duração para 1 consulta: 1.701 seg.
A contagem de linhas não é exata.
Não sou especialista em MySQL ou em banco de dados, mas descobri que, para tabelas muito grandes, você pode usar a opção 2 ou 3 e obter uma 'boa idéia' de quantas linhas estão presentes.
Eu precisava obter essas contagens de linha para exibir algumas estatísticas na interface do usuário. Com as consultas acima, eu sabia que o total de linhas era superior a 500.000, por isso criei estatísticas como "Mais de 500.000 linhas" sem mostrar o número exato de linhas.
Talvez eu realmente não tenha respondido à pergunta do OP, mas estou compartilhando o que fiz em uma situação em que essas estatísticas eram necessárias. No meu caso, mostrar as linhas aproximadas era aceitável e, portanto, o acima funcionou para mim.
fonte
Não é exatamente uma solução independente de DBMS, mas pelo menos o código do seu cliente não verá a diferença ...
Crie outra tabela T com apenas uma linha e um campo inteiro N 1 e crie INSERT TRIGGER que apenas executa:
Crie também um DELETE TRIGGER que executa:
Um DBMS digno de seu sal garantirá a atomicidade das operações acima de 2 , e N conterá a contagem precisa de linhas em todos os momentos, o que é super rápido para simplificar:
Embora os acionadores sejam específicos do DBMS, a seleção de T não é e o código do seu cliente não precisará ser alterado para cada DBMS suportado.
No entanto, isso pode ter alguns problemas de escalabilidade se a tabela for intensiva em INSERT ou DELETE, especialmente se você não confirmar imediatamente após INSERT / DELETE.
1 Esses nomes são apenas espaços reservados - use algo mais significativo na produção.
2 Ie N não pode ser alterado por uma transação simultânea entre leitura e gravação para N, desde que a leitura e a gravação sejam feitas em uma única instrução SQL.
fonte
Uma resposta literalmente insana, mas se você tiver algum tipo de sistema de replicação configurado (para um sistema com um bilhão de linhas, espero que sim), você pode usar um estimador aproximado (como
MAX(pk)
), dividir esse valor pelo número de escravos você tem, execute várias consultas em paralelo.Na maioria das vezes, você particionaria as consultas entre os escravos com base na melhor chave (ou na chave primária, eu acho), de tal maneira (usaremos 250000000 como nossas Linhas / escravos):
Mas você precisa apenas de SQL. Que busto. Ok, então vamos dizer que você é um sadomasoquista. No mestre (ou escravo mais próximo), você provavelmente precisará criar uma tabela para isso:
Portanto, em vez de ter apenas os seletores em execução em seus escravos, você teria que fazer uma inserção, semelhante a isso:
Você pode ter problemas com os escravos escrevendo para uma tabela no mestre. Você pode precisar ficar ainda mais triste - quero dizer, criativo:
No final, você deve ter um escravo que exista por último no caminho percorrido pelo gráfico de replicação, em relação ao primeiro escravo. Esse escravo agora deve ter todos os outros valores de contador e deve ter seus próprios valores. Porém, quando você terminar, provavelmente haverá linhas adicionadas; portanto, você deverá inserir outra para compensar o valor máximo de gravação registrado na sua counter_table e o valor máximo de atualização atual.
Nesse ponto, você teria que fazer uma função agregada para descobrir qual é o total de linhas, mas isso é mais fácil, pois você a executaria no máximo com o "número de escravos que você possui e altera".
Se você estiver na situação em que possui tabelas separadas nos escravos, poderá
UNION
obter todas as linhas necessárias.Ou você sabe, seja um pouco menos insano e migre seus dados para um sistema de processamento distribuído, ou talvez use uma solução Data Warehousing (que também fornecerá dados impressionantes no futuro).
Observe que isso depende de quão bem sua replicação está configurada. Como o gargalo primário provavelmente será o armazenamento persistente, se você tiver armazenamento bruto ou armazenamentos de dados mal segregados com alto ruído do vizinho, provavelmente será mais lento do que apenas esperar por um único
SELECT COUNT(*) ...
Mas se você tiver uma boa replicação, seus ganhos de velocidade deverão estar diretamente relacionados ao número ou escravos. De fato, se levar 10 minutos para executar a consulta de contagem sozinho e você tiver 8 escravos, reduzirá seu tempo para menos de alguns minutos. Talvez uma hora para resolver os detalhes desta solução.
Obviamente, você nunca obteria uma resposta incrivelmente precisa, pois essa solução distribuída introduz um pouco de tempo em que as linhas podem ser excluídas e inseridas, mas você pode tentar obter um bloqueio distribuído de linhas na mesma instância e obter uma contagem precisa das linhas da tabela por um momento específico.
Na verdade, isso parece impossível, já que você está basicamente preso a uma solução somente para SQL e não acho que tenha fornecido um mecanismo para executar uma consulta fragmentada e bloqueada em vários escravos, instantaneamente. Talvez se você tivesse o controle do arquivo de log de replicação ... o que significa que você literalmente criaria escravos para esse fim, o que é sem dúvida mais lento do que executar a consulta de contagem em uma única máquina de qualquer maneira.
Então, há meus dois centavos de 2013.
fonte
Se o gatilho de inserção for muito caro de usar, mas um gatilho de exclusão puder ser fornecido, e houver um incremento automático
id
, depois de contar a tabela inteira uma vez e lembrar a contagem comolast-count
elast-counted-id
,então todos os dias precisam contar
id
>last-counted-id
, adicionarlast-count
e armazenar o novolast-counted-id
.O gatilho de exclusão diminuiria a última contagem, se o ID do registro excluído <= último-contado-id.
fonte
Se você tiver uma estrutura de tabela típica com uma coluna de chave primária de incremento automático na qual as linhas nunca são excluídas, a seguir será a maneira mais rápida de determinar a contagem de registros e deve funcionar de maneira semelhante na maioria dos bancos de dados compatíveis com ANSI:
Trabalho com tabelas do MS SQL que contêm bilhões de linhas que requerem tempos de resposta em segundos para dados, incluindo contagens de registros. Uma CONTAGEM SELECIONADA semelhante (*) levaria alguns minutos para ser processada por comparação.
fonte
INSERT
transação for revertida? Esse valor da chave primária estaria ausente, portanto, a contagem real de registros seria um a menos que o valor máximo.count(*)
, se um fornecedor de banco de dados não tiver sido suficientemente otimizadocount(*)
: Todos os dias, acompanhe o último índice automático e sua contagem correspondente e peça uma contagem de registros além disso. Também pode lidar comdelete
s se adicionar um gatilho na exclusão que diminua o total anterior , se o ID do registro excluído <= esse último índice automático.Para servidor Sql, tente isso
fonte
selecione linhas de sysindexes em que id = Object_ID ('TableName') e indid <2
fonte
Coloque um índice em alguma coluna. Isso deve permitir que o otimizador execute uma varredura completa dos blocos de índice, em vez de uma varredura completa da tabela. Isso reduzirá seus custos de IO. Veja o plano de execução antes e depois. Meça o tempo do relógio de parede nos dois sentidos.
fonte
Se você estiver usando o Oracle, que tal isso (supondo que as estatísticas da tabela sejam atualizadas):
last_analyzed mostrará a hora em que as estatísticas foram coletadas pela última vez.
fonte
Com o PostgreSQL:
fonte
No SQL Server 2016, posso apenas verificar as propriedades da tabela e selecionar a guia 'Armazenamento' - isso fornece contagem de linhas, espaço em disco usado pela tabela, espaço de índice usado etc.
fonte
database vendor independent solution
. Além disso, isso requer uma GUI e não pode ser automatizado. Também não é mais rápido como COUNT (*)Talvez um pouco tarde, mas isso pode ajudar outras pessoas no MSSQL
fonte