No nosso último post, nós desbravamos o universo dos JOINs e vimos como conectar tabelas diferentes. Mas quem trabalha com dados ou DevOps sabe que, mais cedo ou mais tarde, aquela query com múltiplos JOINs, filtros e agrupamentos vai começar a arrastar em produção.
Quando uma query demora para responder, o pior caminho é tentar adivinhar o problema (“acho que falta um índice aqui”, “talvez o banco esteja sem memória”). No PostgreSQL, nós não adivinhamos. Nós perguntamos direto para o otimizador do banco usando a ferramenta definitiva de diagnóstico: o comando EXPLAIN.
Neste post, você vai aprender a ler o plano de execução do Postgres e descobrir exatamente onde as suas consultas estão engasgando.
O que é o EXPLAIN?
O EXPLAIN é um comando que você coloca antes da sua query (SELECT, INSERT, UPDATE ou DELETE). Em vez de simplesmente rodar a consulta e trazer os dados, ele pede para o otimizador do PostgreSQL revelar o seu Plano de Execução.
O plano de execução é o mapa rodoviário que o banco desenhou para buscar os seus dados. Ele mostra se o banco vai usar um índice, se vai ler a tabela inteira do disco, qual algoritmo de JOIN ele escolheu e o custo estimado de processamento.
A Sintaxe Essencial
Existem duas formas principais de usar esse comando.
1. EXPLAIN simples (Estimativa)
Mostra apenas o plano baseado nas estatísticas que o banco já tem guardadas na memória. Ele não executa a query, sendo 100% seguro para rodar em produção a qualquer momento.
EXPLAIN SELECT * FROM servidores WHERE status = 'ativo';
2. EXPLAIN ANALYZE (A Realidade)
Este é o verdadeiro raio-X. Ele executa a query em segundo plano, mede o tempo real em milissegundos, conta as linhas reais e compara com a estimativa do banco.
⚠️ Atenção DevOps/DBA: Como o
EXPLAIN ANALYZEexecuta a query de verdade, se você rodá-lo com umDELETEouUPDATE, a alteração vai acontecer no banco. Se for testar comandos de escrita, use uma transação comROLLBACK.
EXPLAIN ANALYZE SELECT * FROM servidores WHERE status = 'ativo';
Aprendendo a ler a saída do EXPLAIN
A saída do EXPLAIN é uma árvore de texto lida de baixo para cima e de dentro para fora. Vamos ver um exemplo de saída simplificada de um scan sequencial:
Seq Scan on servidores (cost=0.00..35.50 rows=12 width=146) (actual time=0.015..0.082 rows=15 loops=1)
Planning Time: 0.065 ms
Execution Time: 0.120 ms
O que significam esses termos?
Seq Scan: O maior vilão da performance. Significa que o Postgres ignorou (ou não encontrou) índices e leu a tabela linha por linha do disco. Se sua tabela tiver milhões de linhas, isso vai derrubar o banco.cost=0.00..35.50: O primeiro número (0.00) é o custo para iniciar a operação (trazer a primeira linha). O segundo número (35.50) é a estimativa de custo total para finalizar a operação. Esse “custo” é uma unidade arbitrária do Postgres baseada em acessos a páginas de disco e uso de CPU.rows=12: Quantas linhas o otimizador acha que vai encontrar.actual time=0.015..0.082: O tempo real em milissegundos que levou para processar a primeira e a última linha (só aparece se usarANALYZE).Execution Time: O tempo total que a query levou para rodar e entregar o resultado.
O Cenário Ideal: Index Scan
Agora, imagine que nós adicionamos um índice na coluna status e rodamos o mesmo comando. A saída muda para algo assim:
Index Scan using idx_servidores_status on servidores (cost=0.28..8.30 rows=12 width=146) ...
Index Scan: Sucesso! O banco usou o índiceidx_servidores_statuspara ir direto na página de disco correta, reduzindo o custo total de35.50para8.30.
Indicadores de Problemas (O que procurar no seu EXPLAIN)
Quando você estiver analisando uma query lenta, procure por estes três sinais vermelhos:
- Seq Scan em tabelas grandes: Se a tabela tiver mais de algumas dezenas de milhares de linhas e estiver exibindo
Seq Scan, você provavelmente precisa de um índice na coluna doWHEREou doJOIN. - Discrepância gigante em
rowsvsactual rows: Se o banco estima que vai retornar 10 linhas (rows=10), mas na prática retornou 1 milhão (actual rows=1000000), as estatísticas do seu banco estão desatualizadas. O comandoANALYZE nome_da_tabela;pode resolver isso. - Filter removendo muitas linhas: Se você ver um
Seq Scanseguido de umFilter: (coluna = 'valor')que descarta 99% das linhas da tabela, um índice B-Tree nessa coluna faria a query voar.
Conclusão
O comando EXPLAIN é a ferramenta que separa quem “chuta” soluções de quem realmente entende o comportamento do banco de dados. Incorporar o hábito de rodar um EXPLAIN ANALYZE durante o desenvolvimento de novas queries evita que códigos ineficientes cheguem ao ambiente de produção e causem incidentes de infraestrutura.
Com esse post, fechamos os conceitos fundamentais de estrutura, manipulação e diagnóstico de performance em tabelas relacionais.
No próximo post da nossa seção de SQL, vamos mergulhar nas Views (Visualizações). Vamos aprender como simplificar queries complexas e reutilizar regras de negócio sem precisar reescrever linhas e linhas de código SQL. Até lá!
Você já tomou um susto ao rodar um EXPLAIN e ver um Seq Scan em uma tabela de produção? Deixe seu comentário contando como você resolveu esse gargalo!