Plano de execução
Como ler o EXPLAIN para entender por que uma consulta está lenta.
As decisões em torno do plano de execução são quatro: como encontrar as consultas lentas, como investigar cada uma, como corrigir e como impedir que o problema volte.
Como encontrar as consultas lentas
| Ferramenta | O que mostra | Custo |
|---|---|---|
pg_stat_statements | Tempo total, médio e número de execuções de cada consulta, agrupadas pelo formato | Baixo; precisa estar em shared_preload_libraries |
auto_explain | O plano das consultas acima de um tempo, no log | Baixo sem log_analyze; com ele, mede cada consulta |
Log de consultas lentas (log_min_duration_statement) | O texto e a duração das consultas acima de um tempo | Baixo |
| Rastreamento da aplicação | Qual rota disparou qual consulta, e quanto ela pesou no pedido | Depende da ferramenta; ver o tópico de rastreamento |
Comece pelo pg_stat_statements, ordenado pelo tempo total, e não pelo tempo médio. Uma consulta de 2 ms executada um milhão de vezes por dia pesa mais que uma de 3 segundos que roda uma vez. E o caso típico do tópico de ORMs, o N+1, aparece justamente assim: uma consulta rápida, repetida demais.
No MySQL, os equivalentes são o performance_schema e o log de consultas lentas (slow query log), e o EXPLAIN ANALYZE existe a partir da versão 8.0.18.
Como investigar uma consulta
Um roteiro que resolve a maioria dos casos:
- Rode
EXPLAIN (ANALYZE, BUFFERS)com valores reais, num banco com volume parecido com o de produção. Planos mudam com o volume. - Ache o nó mais caro: o de maior
actual timemultiplicado porloops. - Compare
rowsestimado com o real nesse nó e nos de baixo. Uma diferença de dez vezes ou mais aponta estatísticas ruins ou uma condição que o planejador não sabe estimar. - Procure
Seq ScancomRows Removed by Filtergrande: falta índice, ou algo impede o uso dele. - Confira
Buffers: readalto: dados fora da memória, comuns na primeira execução. Rode duas vezes antes de concluir. - Veja
Sort Method: external merge: a ordenação não coube na memória (work_mem).
Planos de texto longos ficam mais fáceis de ler em visualizadores, como o explain.dalibo.com, que destacam o nó mais caro.
Como corrigir
| Sintoma no plano | Causa provável | Correção |
|---|---|---|
Seq Scan com muitas linhas descartadas | Falta índice | Índice nas colunas do WHERE, na ordem certa (ver o tópico de índices) |
Filter com uma função na coluna | Função impede o índice | Índice na expressão, ou reescrever a condição como faixa |
Filter com ::numeric ou outra conversão na coluna | Tipo do parâmetro diferente do da coluna | Corrigir o tipo no código ou no ORM |
Seq Scan com LIKE 'prefixo%' | Collation diferente de C | Índice com text_pattern_ops |
| Estimativa de 1 linha e milhares reais | Estatísticas velhas | ANALYZE; ajustar o autovacuum da tabela |
| Estimativa errada em colunas relacionadas (cidade e estado) | O planejador supõe colunas independentes | Estatísticas estendidas: CREATE STATISTICS |
Sort sobre a tabela inteira com LIMIT | Sem índice na ordem pedida | Índice na coluna do ORDER BY |
Sort Method: external merge | Pouca memória para ordenar | Índice na ordem, ou aumentar work_mem para essa consulta |
Nested Loop com milhares de loops | Estimativa baixa no lado externo | Corrigir a estimativa; raramente, reescrever a consulta |
Evite forçar planos. O PostgreSQL não tem dicas de plano por padrão, de propósito: um plano forçado hoje fica errado quando os dados mudam. Corrija a causa (índice, tipo, estatística), e o planejador escolhe sozinho.
Como impedir que volte
| Prática | Como |
|---|---|
| Teste que confere o uso de índice | Planejar as consultas críticas com enable_seqscan = off e falhar se ainda aparecer Seq Scan, como mostra a Implementação |
EXPLAIN na revisão de código | Consultas novas em tabelas grandes chegam com o plano na descrição da mudança |
ANALYZE depois de cargas | Migrações e importações grandes terminam com ANALYZE nas tabelas afetadas |
| Acompanhamento contínuo | Um painel com as consultas de maior tempo total do pg_stat_statements |
O teste automatizado tem uma armadilha. Em bancos de teste pequenos, o planejador escolhe Seq Scan mesmo com índice, porque ler 10 linhas de uma vez é mais barato. No teste da Implementação, uma tabela vazia com índice mostrou Seq Scan no plano padrão. Desligar a varredura completa (enable_seqscan = off) resolve: com ela desligada, o Seq Scan só aparece quando nenhum índice serve para a consulta.
Resumo da decisão
pg_stat_statementspara achar as consultas de maior tempo total.EXPLAIN (ANALYZE, BUFFERS)com volume realista, olhando o nó mais caro e a diferença entre estimado e real.- Corrigir a causa: índice, expressão, tipo, estatística. Não forçar o plano.
ANALYZEdepois de cargas grandes.- Teste automatizado do uso de índice nas consultas críticas, com
enable_seqscan = off.
O próximo nível mostra esse teste nas cinco linguagens e os comandos de investigação.
Prompts para aprofundar
Ao abrir no ChatGPT ou no Claude, o prompt é enviado ao serviço escolhido pela URL e também fica copiado na sua área de transferência.
Investigar uma consulta lenta
Tenho uma consulta lenta e quero investigá-la com método. Pergunte qual banco e versão eu uso, peça a consulta, o volume das tabelas envolvidas e os índices existentes, e depois a saída do EXPLAIN (ANALYZE, BUFFERS). Me guie: 1. Qual é o nó mais caro. 2. Onde as estimativas erram, e por quê. 3. Qual é a causa provável. 4. Qual é a correção, e como confirmar com um novo plano. Não proponha índices sem antes olhar o plano.
Montar o acompanhamento de consultas lentas
Quero acompanhar as consultas lentas do meu banco em produção. Pergunte qual banco, versão e serviço gerenciado eu uso, e que ferramentas de observabilidade já existem. Monte comigo: 1. A configuração do pg_stat_statements (ou equivalente) e do log de consultas lentas. 2. O auto_explain, com os limites certos para não pesar no banco. 3. As consultas para achar o maior tempo total e as que mais pioraram. 4. Como ligar uma consulta lenta à rota da aplicação que a disparou. 5. Uma rotina semanal de revisão.
Estatísticas e planos instáveis
Algumas consultas do meu sistema ficam lentas de vez em quando, sem mudança no código. Pergunte qual banco eu uso, como os dados chegam (cargas grandes, importações) e como o autovacuum está configurado. Explique: 1. Como as estatísticas influenciam o plano. 2. Quando o autovacuum demora a atualizá-las, e como ajustar por tabela. 3. Estatísticas estendidas para colunas relacionadas. 4. O efeito de parâmetros diferentes no mesmo formato de consulta. 5. Como confirmar que o problema é de estatística, com os comandos.