Aprenda / SQL e banco de dados

IntermediárioAula 15 de 1617 min0% da trilha

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

SQL (PostgreSQL)
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

SQL (PostgreSQL)
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:

motivos comuns
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.
SQL — índice de expressão pro caso da função
-- í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.

Quiz rápido

Numa saída de EXPLAIN ANALYZE, qual a diferença entre 'Seq Scan' e 'Index Scan'?
Cite um motivo real pelo qual o planner pode decidir ignorar um índice que existe na coluna do WHERE.