Estou tentando COUNT(*)
uma tabela com 150.000 linhas que possui uma chave primária. Demorou cerca de 5 minutos, então descobri que é um problema de indexação.
Citando o manual do PostgreSQL :
REINDEX é semelhante a descartar e recriar o índice, pois o conteúdo do índice é reconstruído do zero. No entanto, as considerações de bloqueio são bastante diferentes. REINDEX bloqueia gravações, mas não leituras da tabela pai do índice. Ele também requer um bloqueio exclusivo no índice específico que está sendo processado, o que bloqueará as leituras que tentarem usar esse índice (...) O CREATE INDEX subsequente bloqueia as gravações, mas não as leituras; como o índice não está lá, nenhuma leitura tentará usá-lo, o que significa que não haverá bloqueio, mas as leituras podem ser forçadas a varreduras sequenciais caras.
De sua própria experiência, você pode dizer:
- é
REINDEXING
perigoso? Isso pode prejudicar a consistência dos dados? - Pode levar muito tempo?
- É uma solução provável para o meu cenário?
Atualizar:
A solução que funcionou para nós foi recriar o mesmo índice com um nome diferente e, em seguida, excluir o índice antigo.
A criação do índice é muito rápida e reduzimos o tamanho do índice de 650 MB para 8 MB. Usar um COUNT(*)
with between
leva apenas 3 segundos.
A reindexação não é perigosa e não pode prejudicar a consistência dos dados. No entanto, se você tiver gravações críticas de tempo, poderá perder dados se a tabela estiver bloqueada e o DML for abortado.
A reindexação não deve levar muito tempo, mas geralmente envolve a leitura de toda a tabela, a classificação dos campos de índice e a gravação de um novo índice. Dado o tempo para
COUNT(*)
isso, provavelmente levará cinco minutos ou mais.É improvável que seja um problema de indexação.
COUNT(*)
deve usar uma varredura de tabela, caso em que nenhum índice é lido. Eu esperaria que você tivesse algum tipo de problema de IO.Tente usar
COUNT(1)
ouCOUNT(pk_field)
que pode usar o índice.Se você estiver executando em uma plataforma Unix ou Linux, talvez queira monitorar a atividade do disco com
sar
. Você também pode ter um disco com falha que pode reduzir drasticamente as taxas de E/S.Tabelas com objetos grandes também podem aumentar significativamente o IO para construir os registros para COUNT(*).
Não tenho certeza da melhor resposta para você. No entanto, este tópico parece oferecer algumas boas sugestões:n http://postgresql.1045698.n5.nabble.com/count-performance-issue-td2067873.html
Uma observação é que você pode implementar um TRIGGER para manter as contagens de linhas em uma tabela separada (se COUNT(*) for chamado com frequência por seus aplicativos).
Algumas das respostas sugerem que isso é sintomático de um banco de dados que não foi aspirado recentemente (sugerindo que o autovacuum está desativado em seu servidor ou para esse banco de dados em particular)?
Outra sugestão se parece com:
E alguém identificado como A. Kretschmer observa:
Não. A implementação do índice atual não contém informações sobre a visibilidade da linha na transação atual. Você precisa verificar toda a tabela de dados para obter se a linha atual está visível na transação atual.
... apoiando meu comentário sobre as permissões em nível de linha serem uma preocupação de desempenho.
Minha pesquisa também revelou WikiVS: MySQL vs. PostgreSQL: COUNT(*) .
Você pode examinar os outros resultados que encontrei usando Google:postgresql count(*) performance