Regras de Índice e Consulta
Padrões de consulta e índice evitam regressões em produção quando ORMs geram SQL que os revisores nunca veem até que a latência p99 dispare.
Receita
EXPLAIN (ANALYZE, BUFFERS, FORMAT TEXT)
SELECT o.id, o.status, o.placed_at
FROM app.orders o
WHERE o.customer_id = $1
AND o.status = 'open'
ORDER BY o.placed_at DESC
LIMIT 50;Gate: Sem loop aninhado em scan sequencial de milhões de linhas para caminhos de acesso quente da API. Requer plano amigável a índice ou exceção documentada no PR.
Quando usar: Revisão de consulta de API, políticas de acesso de BI e aprovação de SME em SQL gerado por ORM.
Exemplo de Trabalho
-- Consulta de suporte ao endpoint de lista da API
CREATE INDEX idx_orders_customer_status_placed
ON app.orders (customer_id, status, placed_at DESC)
WHERE status IN ('open', 'pending');
EXPLAIN (ANALYZE, BUFFERS)
SELECT id, status, placed_at
FROM app.orders
WHERE customer_id = 42
AND status IN ('open', 'pending')
ORDER BY placed_at DESC
LIMIT 50;Checklist de revisão para PR:
-
LIMITou intervalo de datas limitado presente -
EXPLAINusa scan de índice ou scan de índice bitmap em tabela grande - Sem
SELECT *em tabelas JSONB largas em caminhos de acesso quente - Chaves de junção indexadas em ambos os lados para junções frequentes
- Tempo médio de
pg_stat_statementsregistrado para a consulta alterada
Análise Profunda
Regras em Resumo
| Regra | Justificativa |
|---|---|
| EXPLAIN antes do merge | Captura surpresas do planejador pré-produção |
| Contagens de linhas limitadas em APIs | Evita OOM e contas descontroladas |
| Colunas de predicado de índice à esquerda | Correspondência de prefixo Btree |
| Evitar funções em colunas indexadas em WHERE | A menos que um índice de expressão exista |
| Revisar padrões de ORM N+1 | Centenas de buscas de linha única |
Anti-Padrões de Consulta de API
-- RUIM: ilimitado
SELECT * FROM app.events WHERE tenant_id = $1;
-- BOM: paginação por cursor ou keyset
SELECT id, created_at, type
FROM app.events
WHERE tenant_id = $1 AND created_at < $2
ORDER BY created_at DESC
LIMIT 100;Quando o Scan Sequencial é OK
- Tabelas pequenas (< alguns milhares de linhas) por estimativa de linha do
EXPLAIN - Trabalhos em lote analíticos fora da réplica com
statement_timeoutexplícito - Pós-migração antes do
ANALYZE- temporário, não aceito para API de produção
Disciplina de Índice
-- Um propósito claro por índice
CREATE INDEX idx_events_tenant_created
ON app.events (tenant_id, created_at DESC);- Remover índices redundantes
(tenant_id)quando(tenant_id, created_at)existe - Índices parciais para filas filtradas por status
Armadilhas
- ORM oculta LIMIT - Tamanho de página padrão ilimitado em visualizações administrativas. Correção: Tamanho máximo de página no lado do servidor de 100-500.
- LIKE '%foo' - Caractere curinga inicial não pode usar btree. Correção: GIN trigram ou busca de texto completo.
- Ordem composta errada - Índice
(status, customer_id)mas consulta filtracustomer_idprimeiro. Correção: Corresponder à ordem de seletividade do filtro. - Estatísticas desatualizadas após carga em massa - O planejador escolhe scan sequencial. Correção:
ANALYZEno pipeline de migração. - Plano genérico de instrução preparada - PG 12+ pode mudar para um plano genérico subótimo. Correção: Monitorar após a implantação; ajustar
plan_cache_modese necessário.
Alternativas
| Alternativa | Usar Quando | Não Usar Quando |
|---|---|---|
| View materializada | Padrão de leitura caro e estável | Consistência em tempo real necessária |
| Roteamento de réplica de leitura | Relatórios pesados | Necessidade das últimas escritas |
INCLUDE de índice de cobertura | Ganho de scan apenas por índice | Amplificação de escrita muito alta |
FAQs
EXPLAIN sem ANALYZE é suficiente?
Para novas consultas em tabelas grandes, use ANALYZE em staging com volume de dados realista. BUFFERS mostra amplificação de leitura.
Quem é responsável pela revisão de consultas?
Autor do aplicativo + DBA/SME em caminhos de acesso quente. Automatize alertas de regressão de pg_stat_statements em equipes maduras.
Exceção de SQL bruto do ORM?
Não - SQL bruto ainda precisa das regras EXPLAIN e LIMIT.
Relacionado
- Desempenho RLS - índices de coluna de política
- Checklist de Regras do Projeto Postgres - regras 6-10
- Melhores Práticas do Cliente psql - hábitos do analista
Versões da Pilha: Esta página foi escrita para PostgreSQL 18.4 (estável 18, manutenção 17), pgvector 0.8+, PgBouncer 1.x, Patroni 3.x e PostGIS 3.5+.