EXPLAIN e otimização de queries
Criar o índice não é o fim da história — o planner pode decidir não usá-lo, e EXPLAIN ANALYZE é como você descobre por quê.
Na lição 6, EXPLAIN apareceu como uma única linha confirmando "Index Scan". O output real de EXPLAIN ANALYZE traz muito mais que isso — e é comum criar um índice certinho e ainda assim ver o banco decidir não usá-lo. Não é bug: é o planner fazendo uma escolha, e dá pra entender qual.
Antes do índice — lendo um EXPLAIN ANALYZE completo
EXPLAIN ANALYZE SELECT * FROM pedidos WHERE usuario_id = 42;Seq Scan confirma que o banco varreu a tabela inteira. cost=0.00..2200.00 é a estimativa de custo antes de rodar (arranque..total, numa unidade arbitrária do planner, não milissegundos) — serve pra comparar planos entre si, não pra medir tempo real. actual time=0.008..18.412 já é tempo medido de verdade, porque ANALYZE manda o Postgres executar a consulta, não só estimar. Rows Removed by Filter: 99994 mostra o preço do Seq Scan: quase 100 mil linhas lidas e descartadas só pra achar as 6 que interessavam.
Depois do índice — o mesmo EXPLAIN, plano diferente
CREATE INDEX idx_pedidos_usuario_id ON pedidos (usuario_id);
EXPLAIN ANALYZE SELECT * FROM pedidos WHERE usuario_id = 42;O custo estimado caiu de 2200.00 pra 8.31, e o tempo de execução real caiu de ~18ms pra ~0.04ms — sem Rows Removed by Filter nenhum, porque o Index Scan vai direto nas linhas certas em vez de varrer tudo.
Quando o planner ignora um índice que existe
Criar o índice não garante que ele sempre será usado — o planner escolhe pelo custo estimado, não por "existe índice, então usa". Alguns motivos comuns pra ele preferir Seq Scan mesmo com índice disponível:
1. Tabela pequena — ler tudo sequencialmente já é barato o
suficiente; abrir o índice teria um custo relativo maior.
2. Baixa seletividade — se o filtro combina com uma fração grande
da tabela (ex.: 40% das linhas), varrer tudo pode sair mais
barato do que ficar saltando entre índice e tabela.
3. Estatísticas desatualizadas — o planner decide com base em
estatísticas de distribuição de dado. Se a tabela mudou muito
e ninguém rodou ANALYZE nome_da_tabela;, a estimativa de custo
pode estar errada.
4. Função aplicada na coluna indexada — WHERE LOWER(email) = ...
não usa um índice normal em email; precisaria de um índice
sobre a expressão LOWER(email) especificamente.-- índice comum em email não ajuda aqui:
SELECT * FROM usuarios WHERE LOWER(email) = 'ana@exemplo.com';
-- índice sobre a expressão, sim:
CREATE INDEX idx_usuarios_email_lower ON usuarios (LOWER(email));Exercício
Você roda EXPLAIN ANALYZE numa consulta e vê Seq Scan, mesmo existindo um índice na coluna do WHERE. Cite duas razões plausíveis (vistas nesta lição) pra isso acontecer, sem trocar o índice de coluna.