Como faço para forçar o Postgres a usar um índice quando, de outra forma, ele insistiria em fazer uma varredura sequencial?
sql
postgresql
indexing
mike
fonte
fonte
Respostas:
Supondo que você esteja perguntando sobre o recurso comum de "sugestão de índice" encontrado em muitos bancos de dados, o PostgreSQL não fornece tal recurso. Esta foi uma decisão consciente feita pela equipe do PostgreSQL. Uma boa visão geral do porquê e do que você pode fazer pode ser encontrada aqui . Os motivos são basicamente que é um hack de desempenho que tende a causar mais problemas posteriormente, conforme os dados mudam, enquanto o otimizador do PostgreSQL pode reavaliar o plano com base nas estatísticas. Em outras palavras, o que pode ser um bom plano de consulta hoje provavelmente não será um bom plano de consulta para sempre, e as dicas de índice forçam um plano de consulta específico para todo o tempo.
Como um martelo muito cego, útil para testes, você pode usar os parâmetros
enable_seqscan
eenable_indexscan
. Vejo:enable_
parametrosEles não são adequados para uso em produção contínua . Se você tiver problemas com a escolha do plano de consulta, deverá consultar a documentação para rastrear problemas de desempenho de consulta . Não basta definir
enable_
parâmetros e ir embora.A menos que você tenha um bom motivo para usar o índice, o Postgres pode estar fazendo a escolha correta. Por quê?
Veja também esta postagem de um grupo de notícias antigo .
fonte
Provavelmente, a única razão válida para usar
é quando você está escrevendo consultas e deseja ver rapidamente o que o plano de consulta realmente seria se houvesse grandes quantidades de dados na (s) tabela (s). Ou, claro, se você precisar confirmar rapidamente que sua consulta não está usando um índice simplesmente porque o conjunto de dados é muito pequeno.
fonte
set enable_seqscan=false
, execute sua consulta e, em seguida, execute rapidamenteset enable_seqscan=true
para retornar o postgresql ao seu comportamento adequado (e obviamente não faça isso na produção, apenas no desenvolvimento!)SET SESSION enable_seqscan=false
para afetar apenas a si mesmoÀs vezes, o PostgreSQL falha em fazer a melhor escolha de índices para uma determinada condição. Por exemplo, suponha que haja uma tabela de transações com vários milhões de linhas, das quais existem várias centenas para qualquer dia, e a tabela tem quatro índices: transaction_id, client_id, date e description. Você deseja executar a seguinte consulta:
O PostgreSQL pode escolher usar o índice transactions_description_idx ao invés de transaction_date_idx, o que pode fazer com que a consulta demore vários minutos em vez de menos de um segundo. Se for este o caso, você pode forçar o uso do índice na data falsificando a condição desta forma:
fonte
your_wanted_index
, pode ser que o mecanismo postgresql apenas execute uma varredura de sequência / chave primária. Conclusão - não existe um método 100% confiável para forçar algum uso de índice para o servidor PostgreSql.where
condição além de duas tabelas ou unidas e o Postgres falhar em obter o índice.Resposta curta
Esse problema normalmente ocorre quando o custo estimado de uma varredura de índice é muito alto e não reflete a realidade corretamente. Você pode precisar diminuir o
random_page_cost
parâmetro de configuração para corrigir isso. Da documentação do Postgres :Você pode verificar se um valor menor realmente fará o Postgres usar o índice (mas use-o apenas para teste ):
Você pode restaurar o valor padrão com
SET random_page_cost = DEFAULT;
novamente.fundo
As varreduras de índice requerem buscas de páginas de disco não sequenciais. Postgres usa
random_page_cost
para estimar o custo de tais buscas não sequenciais em relação às buscas sequenciais. O valor padrão é4.0
, assumindo assim um fator de custo médio de 4 em comparação com as buscas sequenciais (levando em consideração os efeitos do cache).O problema, entretanto, é que esse valor padrão não é adequado nos seguintes cenários importantes da vida real:
1) Drives de estado sólido
Como a documentação admite:
De acordo com o último ponto deste slide de uma palestra no PostgresConf 2018,
random_page_cost
deve ser definido como algo entre1.0
e2.0
para drives de estado sólido.2) Dados em cache
Se os dados de índice necessários já estiverem armazenados em cache na RAM, uma varredura de índice sempre será significativamente mais rápida do que uma varredura sequencial. A documentação diz:
O problema é que você não pode saber facilmente se os dados relevantes já estão armazenados em cache. No entanto, se um índice específico for consultado com frequência e se o sistema tiver RAM suficiente, os dados provavelmente serão armazenados em cache e
random_page_cost
deverão ser configurados com um valor inferior. Você terá que experimentar diferentes valores e ver o que funciona para você.Você também pode querer usar a extensão pg_prewarm para armazenamento de dados explícito.
fonte
A pergunta em si é muito inválida. Forçar (fazendo enable_seqscan = off por exemplo) é uma ideia muito ruim. Pode ser útil verificar se será mais rápido, mas o código de produção nunca deve usar esses truques.
Em vez disso - explique a análise de sua consulta, leia-a e descubra por que o PostgreSQL escolheu um plano ruim (em sua opinião).
Existem ferramentas na web que ajudam a ler a saída de explicação e análise - uma delas é explain.depesz.com - escrita por mim.
Outra opção é entrar no canal #postgresql na rede freenode irc, e falar com os caras lá para ajudá-lo - pois otimizar a consulta não é uma questão de "fazer uma pergunta, obter uma resposta ser feliz". é mais como uma conversa, com muitas coisas para checar, muitas coisas para aprender.
fonte
Existe um truque para empurrar o postgres para preferir um seqscan adicionando um
OFFSET 0
na subconsultaIsso é útil para otimizar solicitações que ligam tabelas grandes / enormes quando tudo o que você precisa são apenas os n primeiros / últimos elementos.
Digamos que você esteja procurando pelos primeiros / últimos 20 elementos envolvendo várias tabelas com 100k (ou mais) entradas, não adianta construir / vincular todas as consultas sobre todos os dados quando o que você está procurando está nos primeiros 100 ou 1000 entradas. Neste cenário, por exemplo, é 10x mais rápido fazer uma varredura sequencial.
veja Como posso evitar que o Postgres inlining uma subconsulta?
fonte