O que um índice realmente armazena
Pense no índice como uma estrutura separada da tabela, otimizada para busca. Em termos práticos, ele armazena:
- Chaves do índice: valores de uma ou mais colunas (ex.:
cpf,email,data_pedido), organizados de forma que facilite localizar rapidamente um intervalo ou um valor específico. - Referências (ponteiros): um “endereço” para chegar ao dado real. Dependendo do banco/engine, essa referência pode ser o identificador da linha (RID), a chave primária, ou um ponteiro para a página/slot onde a linha está armazenada.
O ganho vem do fato de que, em vez de ler muitas páginas da tabela procurando linha a linha, o banco navega por poucas páginas do índice (que é menor e ordenado) e chega diretamente às referências das linhas candidatas.
Diagrama conceitual (em texto): índice como lista ordenada + ponteiros
ÍNDICE (chave ordenada) TABELA (linhas reais) [10] -> (página 7, slot 3) ---------> página 7: ... [slot 3] linha id=... [15] -> (página 2, slot 9) ---------> página 2: ... [slot 9] linha id=... [21] -> (página 9, slot 1) ---------> página 9: ... [slot 1] linha id=...
Quando você filtra por chave = 15, o banco tenta achar 15 no índice e, ao encontrar, segue o ponteiro para ler a linha na tabela.
Chave do índice: o que é e por que importa
A chave do índice é o(s) campo(s) usado(s) para ordenar e pesquisar dentro do índice. Ela pode ser:
- Simples: uma coluna (ex.:
cpf). - Composta: várias colunas em ordem (ex.:
(estado, cidade, data_cadastro)).
Na prática, a ordem das colunas em um índice composto define quais predicados conseguem “entrar” no índice de forma eficiente. O banco tende a aproveitar melhor o prefixo da chave (as primeiras colunas).
- Ouça o áudio com a tela desligada
- Ganhe Certificado após a conclusão
- + de 5000 cursos para você explorar!
Baixar o aplicativo
Exemplo rápido: índice composto e prefixo
Índice: (estado, cidade, data_cadastro)
WHERE estado = 'SP'→ consegue buscar um intervalo deestadono índice.WHERE estado = 'SP' AND cidade = 'Campinas'→ intervalo menor, mais seletivo.WHERE cidade = 'Campinas'→ geralmente não usa bem esse índice (falta o prefixoestado), a menos que o otimizador estime que ainda vale a pena por outros motivos.
Cardinalidade, duplicidade e seletividade (o “poder de filtrar”)
Cardinalidade é a quantidade de valores distintos em uma coluna (ou combinação de colunas). Ela influencia o quanto um índice ajuda.
- Alta cardinalidade (muitos valores distintos, ex.:
cpf,email): o índice tende a ser muito útil, porque cada busca retorna poucas linhas. - Baixa cardinalidade (poucos valores distintos, ex.:
statuscom 3 valores): o índice pode ajudar em alguns casos, mas frequentemente retorna muitas linhas e o custo de “ir e voltar” para a tabela pode ficar alto.
Duplicidade é quando muitos registros compartilham o mesmo valor de chave. Índices aceitam duplicidade (a menos que sejam unique), mas isso afeta o custo: encontrar a chave é rápido, porém ler todas as referências associadas pode ser caro.
Microexercício 1: qual índice tende a filtrar melhor?
Uma tabela clientes tem 10 milhões de linhas.
- Coluna
sexo: valores {M, F, N} (3 distintos). - Coluna
cpf: 10 milhões distintos.
Pergunta: em uma consulta que busca um único cliente, qual índice tende a reduzir mais leituras: idx_sexo ou idx_cpf? O que o banco precisaria ler em cada caso?
Páginas, níveis e custo de navegação no índice
Índices são armazenados em páginas (blocos) e, em estruturas comuns como B-Tree/B+Tree, organizados em níveis:
- Raiz (root): ponto de entrada.
- Níveis intermediários: direcionam a busca.
- Folhas (leaf): onde ficam as chaves (ou intervalos) e as referências para as linhas/páginas.
O custo típico de uma busca por igualdade em um índice B-Tree é: ler algumas páginas do índice (uma por nível) até chegar à folha. Depois, para cada linha encontrada, pode haver leituras adicionais na tabela (a menos que o índice “cubra” a consulta, assunto que depende do banco e do tipo de índice).
Diagrama conceitual (em texto): navegação por níveis
[ROOT] / \ [NÓ] [NÓ] / \ / \ [FOLHA][FOLHA][FOLHA][FOLHA] | | | | chaves+refs ...
Se o índice tem 3 níveis, uma busca pode exigir algo como 3 leituras de páginas do índice (root + intermediário + folha), mais as leituras da tabela para buscar as linhas referenciadas.
Microexercício 2: estimando leituras
Imagine:
- Índice com 3 níveis.
- Predicado retorna 200 linhas.
Pergunta: quantas páginas o banco precisa ler no mínimo para localizar as referências (apenas no índice)? E quantas leituras adicionais podem ocorrer ao buscar as 200 linhas na tabela?
Clustering lógico vs físico (conceitual)
É comum confundir “ordem do índice” com “ordem física da tabela”. Conceitualmente:
- Clustering lógico: o índice mantém as chaves em ordem e permite navegar por intervalos (ex.: datas de um mês). Isso é uma propriedade da estrutura do índice.
- Clustering físico: refere-se a como as linhas estão de fato distribuídas nas páginas da tabela. Mesmo que o índice esteja ordenado, as linhas apontadas podem estar espalhadas em muitas páginas.
Quando as linhas correspondentes a um intervalo do índice estão fisicamente próximas, a leitura tende a ser mais sequencial e barata. Quando estão espalhadas, a consulta pode virar muitas leituras aleatórias.
Diagrama conceitual (em texto): mesmo índice, duas distribuições físicas
Caso A (mais agrupado fisicamente): Índice (data) -> refs -> páginas 10,11,12 (poucas páginas) Caso B (mais espalhado fisicamente): Índice (data) -> refs -> páginas 3,18,44,105,... (muitas páginas)
Como o banco transforma um predicado em busca no índice
O otimizador tenta mapear o predicado para um padrão de acesso ao índice. Os padrões mais comuns:
- Busca por igualdade:
col = valor→ navega até a chave e pega as referências. - Busca por intervalo:
col BETWEEN a AND b,col >= a→ navega até o início do intervalo e percorre folhas até o fim. - Prefixo textual:
col LIKE 'abc%'→ pode virar intervalo (abcaté algo comoabd, dependendo de collation/ordenação). - Funções na coluna:
WHERE YEAR(data)=2025→ frequentemente impede o uso direto do índice na coluna, porque o índice está ordenado pelo valor original, não pelo resultado da função.
Exemplo 1 (numérico): igualdade
Tabela: contas(id, saldo). Índice: idx_saldo(saldo).
SELECT id FROM contas WHERE saldo = 1000;Passo a passo do que tende a acontecer:
- O banco identifica que existe índice em
saldo. - Navega pelos níveis do índice até a folha onde
saldo=1000estaria. - Se houver duplicidade (muitas contas com saldo 1000), a folha terá várias referências.
- Para cada referência, lê a linha (ou página) na tabela para retornar
id(a menos que o índice já contenhaidcomo parte da estrutura, dependendo do tipo de índice/engine).
Microexercício 3: duplicidade e custo
Se 50 mil contas têm saldo=1000, o índice ainda ajuda? Pergunta: o que fica barato (localizar a chave) e o que pode ficar caro (buscar muitas linhas)?
Exemplo 2 (texto): busca por prefixo
Tabela: usuarios(id, email). Índice: idx_email(email).
SELECT id FROM usuarios WHERE email LIKE 'ana%';Como isso pode virar uma busca no índice:
- O banco interpreta
'ana%'como um intervalo de chaves que começam comana. - Navega até a primeira chave que atende (ex.:
ana...). - Percorre as folhas em ordem enquanto as chaves ainda começam com
ana.
Observação prática: LIKE '%ana' (com curinga no início) geralmente não consegue usar o índice como intervalo, porque não há um prefixo fixo para localizar o início.
Microexercício 4: qual predicado “entra” no índice?
- A)
email LIKE 'ana%' - B)
email LIKE '%ana'
Pergunta: em qual caso o banco consegue navegar pelo índice começando de um ponto bem definido? O que muda no número de páginas lidas?
Exemplo 3 (datas): intervalo por período
Tabela: pedidos(id, data_pedido, total). Índice: idx_data(data_pedido).
SELECT id, total FROM pedidos WHERE data_pedido BETWEEN '2025-01-01' AND '2025-01-31';Passo a passo típico:
- O banco transforma
BETWEENem um intervalo ordenado. - Navega no índice até a primeira chave
>= '2025-01-01'. - Varre as folhas em ordem até ultrapassar
'2025-01-31'. - Coleta referências e busca as linhas correspondentes na tabela para retornar
idetotal.
Microexercício 5: intervalo pequeno vs grande
Compare:
- A) Um dia:
data_pedido = '2025-01-15' - B) Um ano:
data_pedido BETWEEN '2025-01-01' AND '2025-12-31'
Pergunta: qual tende a percorrer mais páginas de folha do índice? Em qual caso a busca na tabela pode virar o maior custo?
Quando o índice aponta para a linha: ponteiros e “volta” à tabela
Após localizar as chaves no índice, o banco segue as referências para obter as colunas solicitadas. Isso cria um padrão comum:
- Índice filtra: encontra rapidamente as chaves candidatas.
- Tabela confirma e retorna: lê as linhas para pegar as demais colunas.
Se a consulta retorna poucas linhas, essa “volta” é barata. Se retorna muitas, o custo de buscar linha a linha pode superar o ganho do índice.
Diagrama conceitual (em texto): custo dividido
Custo total ≈ (leituras para navegar no índice) + (leituras para buscar linhas na tabela) Navegação no índice: poucas páginas (níveis) Busca na tabela: depende de quantas linhas e quão espalhadas estão
Checklist mental: “o que o banco precisa ler para responder?”
Ao olhar uma consulta com filtro, treine a estimar leituras respondendo:
- Existe índice na(s) coluna(s) do predicado?
- O predicado é igualdade, intervalo, prefixo, ou envolve função na coluna?
- Quantas linhas o predicado tende a retornar (seletividade)?
- Há muita duplicidade na chave?
- Quantos níveis o índice provavelmente tem (tamanho do índice)?
- As linhas estão fisicamente agrupadas ou espalhadas (clustering físico)?
Microexercício 6: interpretação guiada
Considere a tabela eventos(id, tipo, data_evento, usuario_id) com 100 milhões de linhas. Índices: idx_tipo(tipo) e idx_data(data_evento).
SELECT COUNT(*) FROM eventos WHERE tipo = 'LOGIN' AND data_evento >= '2026-01-01';Perguntas:
- Qual predicado parece mais seletivo:
tipo(baixa cardinalidade) oudata_evento(muitos valores)? - Se o banco usar
idx_tipo, o que ele precisará ler depois para aplicar o filtro de data? - Se usar
idx_data, o que ele precisará ler depois para aplicar o filtro de tipo?
Use essas perguntas para treinar a intuição: índice não é “mágica”; ele reduz leituras quando consegue restringir cedo o conjunto de linhas, com navegação barata e poucas voltas à tabela.