O REINDEX é perigoso?

17

Eu tenho tentado COUNT(*)uma tabela com 150.000 linhas que tem uma chave primária. É ferramenta cerca de 5 minutos, então eu descobri que este é um problema de indexação.

Citando o manual do PostgreSQL :

O REINDEX é semelhante a uma remoção e recriação do í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. Também é necessário um bloqueio exclusivo no índice específico que está sendo processado, o que bloqueará as leituras que tentam usar esse índice (...) O subsequente CREATE INDEX bloqueia gravações, mas não 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 verificações seqüenciais caras.

A partir de sua própria experiência, você pode dizer:

  • é REINDEXINGperigoso? Isso pode prejudicar a consistência dos dados?
  • Pode demorar 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 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(*)com betweenleva apenas 3 segundos.

Adam Matan
fonte

Respostas:

15

A reindexação não é perigosa e não pode prejudicar a consistência dos dados. No entanto, se você tiver gravações com tempo crítico, poderá perder dados se a tabela estiver bloqueada e o DML for abortado.

A reindexação não deve demorar muito, 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 necessário COUNT(*), provavelmente levará cinco minutos ou mais.

É improvável que este 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)ou COUNT(pk_field)que pode usar o índice.

Se você estiver executando em uma plataforma Unix ou Linux, poderá monitorar a atividade do disco 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 o IO significativamente para construir os registros para COUNT (*).

BillThor
fonte
2
De acordo com wiki.postgresql.org, COUNT(*)é a melhor escolha:If you are using count(*), the database is free to use any column to count, which means it can pick the smallest covering index to scan (note that this is why count(*) is much better than count(some_field), as long as you don't care if null values of some_field are counted). Since indexes often fit entirely in memory, this means count(*) is often very fast.
orange80
1

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 (*) fosse chamado com freqüência por seus aplicativos).

Algumas das respostas sugerem que isso é sintomático de um banco de dados que não foi aspirado recentemente o suficiente (sugerindo que o autovacuum esteja desativado no seu servidor ou para esse banco de dados em particular)?

Outra sugestão se parece com:

ANALYZE tablename;
SELECT reltuple FROM pg_class WHERE relname = 'tablename';

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 varrer 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 no nível da linha como uma preocupação de desempenho.

Minha pesquisa também descobriu o WikiVS: MySQL vs. PostgreSQL: COUNT (*) .

Você pode ler os outros resultados que encontrei usando o Google: desempenho do postgresql count (*)

Jim Dennis
fonte