Eu tenho uma tabela com vários milhões de registros em um banco de dados PostgreSQL 12 e, após uma atualização de 11 para 12, algumas consultas começaram a ter um desempenho horrível. Eles passaram de ~ 1 segundo para ~ 5 minutos. Tentei reconstruir todos os índices, aspirar e todas as frutas comuns do Postgres, mas o desempenho ainda é terrível.
Esta é a consulta:
SELECT id, activity_count
FROM user
WHERE (search_index) @@ (to_tsquery('pg_catalog.english', '''1234567890'':*') AND active = true
ORDER BY activity_count DESC LIMIT 101
Em outras palavras, encontre todos os usuários ativos correspondentes ao número de conta fornecido e classifique do mais ativo para o menos.
Essa consulta leva cerca de 5 minutos para retornar apenas 2 registros. Alguma coisa não está certa.
A coluna search_index
é um tsvector que armazena todas as palavras-chave dos vários campos de texto da tabela (apenas coisas como account_number, name, etc).
Eu tenho um índice GIN criado para esta coluna com:
CREATE INDEX user_search_index_gin
ON public.user USING gin
(search_index)
TABLESPACE pg_default;
Eu também tenho um índice para a active
coluna com:
CREATE INDEX user_active
ON public.user USING btree
(active ASC NULLS LAST)
TABLESPACE pg_default;
E eu tenho um índice ordenado para o activity_count
com:
CREATE INDEX user_activity_count
ON public.user USING btree
(activity_count ASC NULLS LAST)
TABLESPACE pg_default;
No entanto, quando executo EXPLAIN
, recebo:
"Limit (cost=0.56..11443.66 rows=101 width=1552)"
" -> Index Scan Backward using user_activity_count on user (cost=0.56..36010185.91 rows=317836 width=1552)"
" Filter: (active AND (search_index @@ '''1234567890'':*'::tsquery))"
Por que está usando apenas o índice user_activity_count e não o índice GIN mais eficiente? Como faço para corrigir isso?
Qual índice usar?
Embora suas
WHERE
condições não sejam muito seletivas, o plano de consulta atual faz muito sentido com oORDER BY activity_count DESC LIMIT 101
. Ver:No entanto, seus predicados me parecem bastante seletivos:
Isso é, a menos que seu exemplo
'1234567890'
seja enganoso. (Tem certeza de que deseja as aspas simples no termo de pesquisa?) Obviamente, não é a consulta real que você usou. Parênteses sem correspondência. De qualquer forma, você provavelmente deseja a configuração de pesquisa de texto "simples" (além de algumas melhorias):Ver:
Estatisticas
Portanto, parece que suas estatísticas não estão atualizadas.
Você também adicionou
ANALYZE
à sua cesta todas as frutas comuns do Postgres ? Você certamente não mencionou isso. Considere as instruções do manual :Se o seu banco de dados for grande , você pode estar interessado na
vacuumdb
opção--analyze-in-stages
. (Esse navio pode ter navegado para o caso em questão.) O manual:Relacionado: