Ordem de Índices Multicoluna
Índices compostos B-tree honram as regras de prefixo esquerdo: o planejador pode usar o índice apenas enquanto os predicados corresponderem às colunas líderes na ordem no PostgreSQL 18.4.
Receita
Cartão de receita de referência rápida - pronto para copiar e colar.
-- Bom para: WHERE tenant_id = ? AND status = ? AND created_at > ?
CREATE INDEX events_tenant_status_created_idx
ON events (tenant_id, status, created_at);Quando usar isso: Consultas filtram pela coluna B, mas o índice lidera com a coluna A e os planos mostram seq scan apesar de um índice existente.
Exemplo de Trabalho
CREATE TABLE events (
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
tenant_id int NOT NULL,
status text NOT NULL,
created_at timestamptz NOT NULL DEFAULT now()
);
CREATE INDEX events_wrong_order_idx ON events (status, tenant_id, created_at);
CREATE INDEX events_right_order_idx ON events (tenant_id, status, created_at);
INSERT INTO events (tenant_id, status, created_at)
SELECT
(i % 100) + 1,
CASE WHEN i % 20 = 0 THEN 'failed' ELSE 'ok' END,
now() - (random() * interval '30 days')
FROM generate_series(1, 400000) AS i;
ANALYZE events;
EXPLAIN (ANALYZE, BUFFERS)
SELECT count(*) FROM events
WHERE tenant_id = 7 AND status = 'failed' AND created_at >= now() - interval '1 day';Remova o índice errado em implantações reais após verificar se o índice correto foi escolhido.
O que isso demonstra:
- Colunas de igualdade antes de colunas de intervalo
tenant(seletivo no contexto da aplicação) geralmente liderastatus- O nome do índice em
EXPLAINconfirma qual índice composto está sendo usado
Mergulho Profundo
Como Funciona
- Regra: índice utilizável para predicados em prefixos esquerdos de
(col1),(col1, col2),(col1, col2, col3). - Pular a coluna líder (
WHERE status = ?apenas) não pode usar(tenant_id, status)eficientemente. - Misturar igualdade e intervalo: coloque igualdades primeiro, intervalo por último (
tenant_id =,status =,created_at >). - Direção de ordenação: alinhe
DESCcomORDER BYcomum para evitar ordenações.
Heurísticas de Ordenação
| Prioridade | Posição |
|---|---|
| Filtros de igualdade em toda consulta | Mais à esquerda |
| Igualdade de maior seletividade | Mais à esquerda entre iguais |
| Coluna de intervalo / ordenação | Após igualdades |
| Coluna raramente filtrada | Não incluir |
Notas SQL
-- Dois índices quando duas formas de consulta dominam
CREATE INDEX events_tenant_created_idx ON events (tenant_id, created_at);
CREATE INDEX events_status_created_idx ON events (status, created_at)
WHERE status IN ('failed', 'retry');Armadilhas
- Um mega-índice para todos os relatórios - Não serve bem a nenhuma consulta. Correção: 2-3 compostos comprovados mais índices parciais.
- Coluna líder de baixa cardinalidade -
statusprimeiro quando sempre combinado comtenant_id. Correção: Coloquetenant_idà esquerda, a menos que um índice parcial corrija a fatia destatus. - Coerção implícita de tipo - Incompatibilidade de tipo do predicado pula o índice. Correção: Combine o tipo da coluna em SQL e ORM.
- OR entre colunas - A ordem do índice não pode salvar
ORentre caminhos não prefixados. Correção: Reescrever comUNION ALLou múltiplos índices parciais. - Índices duplicados com colunas permutadas - Amplificação de escrita dobrada. Correção: Auditoria de índice redundante.
Alternativas
| Alternativa | Usar Quando | Não Usar Quando |
|---|---|---|
| Índice parcial por status | Poucos status "quentes" | Centenas de valores de enum |
| Particionamento por tenant | Grandes fatos multi-tenant | Tabela compartilhada pequena |
| Índice de expressão | Função em WHERE | Coluna simples disponível |
FAQs
Ordem tenant_id vs created_at?
Igualdade de tenant_id primeiro quando as consultas sempre escopam o tenant; o intervalo de created_at segue.
O planejador pode pular a coluna do meio?
Geralmente não para B-tree; exceções limitadas (por exemplo, listas IN no meio com igualdade líder).
Colunas INCLUDE?
INCLUDE não afeta a ordem da chave de busca; apenas as colunas chave importam para as regras de prefixo.
Estatísticas multicoluna?
ndistinct estendido em (tenant_id, status) ajuda nas estimativas de cardinalidade de junção.
Index only scan?
Precisa do mapa de visibilidade atualizado e do INCLUDE/lista de seleção cobertos.
Limite de três colunas?
Sem limite rígido; índices práticos ficam com 2-4 colunas chave.
Colunas DESC misturadas?
O PostgreSQL suporta índices multicoluna mistos ASC/DESC desde a v8.3+.
Bitmap AND de índices?
Múltiplos índices de coluna única podem usar bitmap; um bom composto geralmente supera dois fracos.
Ordem de migração?
Crie um novo índice concorrente, verifique o plano, remova o antigo.
Próximo?
Consultas de auditoria de índices duplicados e redundantes.
Relacionado
- Noções Básicas de Design de Índices - Design geral
- Índices Duplicados e Redundantes - Limpeza
- Estatísticas Estendidas -
ndistinctcomposto - Índices Parciais e de Cobertura - Variantes
Versões do Stack: 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+.