O que é um índice composto (multicoluna)
Um índice composto é um único índice que armazena as chaves combinando duas ou mais colunas, por exemplo (A, B). Pense nele como uma lista ordenada primeiro por A e, dentro de cada valor de A, ordenada por B. Essa “ordenação em camadas” é o motivo pelo qual a ordem das colunas no índice muda completamente quais consultas conseguem aproveitar o índice com eficiência.
Exemplo mental rápido
Se você cria INDEX idx_ab (A, B), o banco consegue navegar rapidamente até um valor específico de A e, dentro desse “grupo”, localizar/varrer valores de B. Já se a consulta só fala de B (sem restringir A), o índice não está organizado para começar por B, então a navegação eficiente fica comprometida.
A regra do prefixo (leftmost prefix)
A “regra do prefixo” diz que um índice composto só é usado de forma eficiente quando as condições da consulta começam pela(s) primeira(s) coluna(s) do índice, na mesma ordem. Para um índice (A, B, C), os prefixos úteis são: (A), (A, B) e (A, B, C). Já (B), (C) ou (B, C) não são prefixos e, em geral, não permitem uma busca eficiente pelo índice.
O que significa “usar de forma eficiente”
- Busca pontual (lookup): quando você fixa valores com igualdade (
=) nas primeiras colunas do índice, o banco consegue ir direto ao trecho correto do índice. - Varredura ordenada (range scan): quando você fixa um prefixo e depois faz intervalo/ordenação na próxima coluna, o banco consegue percorrer uma faixa contígua do índice sem precisar ordenar depois.
- Uso parcial: às vezes o índice é usado, mas com baixa eficiência (por exemplo, varrendo muitos registros) porque faltou restringir as primeiras colunas.
Como prever o uso do índice: um checklist prático
Para um índice (A, B), siga este passo a passo para prever se ele ajuda:
- Existe condição em
A? Se não, a regra do prefixo falha (o índice tende a não ajudar para filtrar porB). - Em
A, é igualdade ou intervalo? Igualdade emApermite aproveitarBpara filtrar/ordenar. Intervalo emAnormalmente limita o quantoBpode ser aproveitado. - Existe filtro em
B? SeAestá fixo por igualdade,Bpode ser usado para buscar mais precisamente. - Existe
ORDER BY? Se oORDER BYsegue a ordem do índice e as colunas anteriores estão fixadas adequadamente, o banco pode evitar ordenação extra.
Cenários práticos com (A, B)
Vamos assumir uma tabela pedidos com colunas cliente_id (A) e data_pedido (B). Índice: (cliente_id, data_pedido).
- Ouça o áudio com a tela desligada
- Ganhe Certificado após a conclusão
- + de 5000 cursos para você explorar!
Baixar o aplicativo
CREATE INDEX idx_pedidos_cliente_data ON pedidos (cliente_id, data_pedido);Cenário 1: WHERE A = ? AND B = ?
SELECT * FROM pedidos WHERE cliente_id = 42 AND data_pedido = '2026-01-10';- Previsão: o índice é usado com alta eficiência.
- Por quê: a consulta usa o prefixo completo
(A, B)com igualdade nas duas colunas. O banco encontra diretamente a chave composta correspondente (ou uma faixa mínima, dependendo de duplicidade). - Resultado típico: poucas leituras no índice e poucas leituras na tabela (ou nenhuma, se o índice cobrir as colunas selecionadas).
Cenário 2: WHERE A = ? ORDER BY B
SELECT * FROM pedidos WHERE cliente_id = 42 ORDER BY data_pedido;- Previsão: o índice é usado com alta eficiência para filtrar e para ordenar.
- Por quê:
Aestá fixo por igualdade, então dentro do “grupo” decliente_id = 42o índice já está ordenado porB. Assim, o banco pode retornar as linhas na ordem correta sem um passo extra de sort. - Observação: se você pedir
ORDER BY data_pedido DESC, muitos bancos conseguem percorrer o índice ao contrário e ainda evitar sort.
Cenário 3: WHERE B = ? sem A
SELECT * FROM pedidos WHERE data_pedido = '2026-01-10';- Previsão: o índice
(A, B)tende a não ser usado para filtrar porBde forma eficiente. - Por quê: falta a primeira coluna do índice (
A). Como o índice está ordenado porAprimeiro, os valores deBficam “espalhados” ao longo de muitos grupos deA, impedindo uma busca direta porB. - O que fazer: se esse padrão for frequente e importante, considere um índice separado em
(data_pedido)ou um índice composto com outra ordem, como(data_pedido, cliente_id), dependendo de outros filtros/ordenações.
Ordem das colunas e impacto em filtros e ordenações
Trocar (A, B) por (B, A) muda tudo
Compare as duas consultas abaixo e como elas se encaixam em cada índice:
| Consulta | Índice (A, B) | Índice (B, A) |
|---|---|---|
WHERE A = ? AND B = ? | Ótimo | Ótimo |
WHERE A = ? | Ótimo | Fraco/geralmente não ajuda |
WHERE B = ? | Fraco/geralmente não ajuda | Ótimo |
WHERE A = ? ORDER BY B | Ótimo (evita sort) | Geralmente não evita sort |
WHERE B = ? ORDER BY A | Geralmente não evita sort | Ótimo (evita sort) |
Mesmo quando ambos os índices podem ser usados em WHERE A=? AND B=?, a escolha da ordem é decisiva para consultas que usam apenas uma coluna, ou que dependem de ordenação.
Igualdade antes de intervalo (regra prática importante)
Em índices compostos, condições de igualdade nas primeiras colunas mantêm o índice “bem focado”. Já um intervalo (>, <, BETWEEN, LIKE 'prefix%') tende a abrir uma faixa maior. Depois que você entra em intervalo em uma coluna do índice, o aproveitamento das colunas seguintes para busca/ordenação costuma diminuir.
Exemplo com índice (cliente_id, data_pedido):
SELECT * FROM pedidos WHERE cliente_id = 42 AND data_pedido BETWEEN '2026-01-01' AND '2026-01-31' ORDER BY data_pedido;- Previsão: muito bom. Igualdade em
cliente_ide intervalo emdata_pedido; o índice permite varrer exatamente a faixa de datas daquele cliente já na ordem.
Agora invertendo a lógica (hipotético índice (data_pedido, cliente_id)):
SELECT * FROM pedidos WHERE data_pedido BETWEEN '2026-01-01' AND '2026-01-31' AND cliente_id = 42;- Previsão: pode filtrar pela faixa de datas, mas dentro dessa faixa o
cliente_idpode não ser tão bem aproveitado quanto seria se ele viesse antes, porque o intervalo emdata_pedidojá expandiu a varredura.
Guia rápido: prever eficiência nos três cenários pedidos
1) WHERE A=? AND B=?
- Índice (A, B): uso máximo (lookup altamente seletivo).
- Índice (B, A): também pode ser máximo, mas escolha depende de outras consultas.
2) WHERE A=? ORDER BY B
- Índice (A, B): excelente, filtra por A e já entrega ordenado por B.
- Índice (B, A): não casa com a necessidade; pode exigir sort ou outro plano.
3) WHERE B=? sem A
- Índice (A, B): regra do prefixo falha; tende a não ajudar (ou ajuda pouco).
- Índice (B, A): excelente para filtrar por B.
Heurísticas para definir a ordem das colunas no índice composto
- Priorize o padrão de consulta mais frequente: o melhor índice é o que acelera o que mais roda (e mais custa).
- Seletividade primeiro (na maioria dos casos): coloque antes a coluna que mais reduz o conjunto de linhas quando filtrada por igualdade (ex.:
cliente_idcostuma ser mais seletivo questatus). - Igualdade antes de intervalo: se uma consulta típica tem
WHERE A = ? AND B BETWEEN ..., geralmente(A, B)é uma boa ordem. - Inclua colunas de ordenação logo após as colunas fixadas: para
WHERE A=? ORDER BY B, prefira(A, B)para evitar sort. - Evite “pular” a primeira coluna: se muitas consultas filtram por
BsemA, um índice(A, B)não atende bem; considere(B)ou(B, A)conforme o restante do workload. - Não tente um índice composto para tudo: às vezes dois índices menores (um para
Ae outro paraB) atendem melhor padrões diferentes do que um único composto mal ordenado.