Índices de Banco de Dados: Como Funcionam e Como Usá-los para Melhorar Consultas

Índices de Banco de Dados: Como Funcionam e Como Usá-los para Melhorar Consultas

“`html





Índices de Banco de Dados: Como Funcionam


Índices de Banco de Dados: como funcionam

Índices não são “atalhos mágicos”: eles alteram o caminho de execução do banco, trocando custo de escrita e espaço por
ganhos na leitura. Neste post eu explico, de forma técnica e prática, como os índices funcionam por baixo dos panos e
como isso impacta desempenho.

B-Trees / páginas
seletividade
custo de manutenção
ordem de colunas


1 O que é um índice (e o que ele realmente guarda)

Um índice é uma estrutura auxiliar mantida pelo banco para acelerar operações como busca,
filtro e ordenação. Em vez de varrer uma tabela inteira,
o otimizador pode usar o índice para localizar rapidamente um conjunto menor de registros.

Na prática, o índice mapeia um valor de chave (uma ou mais colunas) para um local
da linha. Dependendo do banco, esse “local” pode ser:

  • RID/TID (identificador físico da linha), ou
  • ponteiro lógico para localizar a linha (por exemplo, via heap / clustered index).
Ideia-chave: o banco não consulta a “tabela pelo índice” — ele consulta o índice para descobrir
onde estão as linhas, e só então acessa a tabela para retornar os dados.

2 Como o banco usa o índice: plano de execução e seletividade

Mesmo que um índice exista, o banco só vai usá-lo se fizer sentido. O otimizador escolhe um plano (estratégia) avaliando
estatísticas como:

  • cardinalidade (quantidade de valores distintos)
  • distribuição dos valores (parte deles pode ser muito comum)
  • seletividade do filtro (fração estimada de linhas retornadas)
  • custo de leituras adicionais e possíveis etapas extras

Em termos simplificados:
se o filtro retorna uma fração pequena da tabela, um índice tende a ajudar.
se retorna quase tudo, uma varredura sequencial pode ser mais barata.

Observação prática: você sempre quer validar com o EXPLAIN/EXPLAIN ANALYZE. Índice não é garantia,
é uma opção de caminho.

3 Estruturas comuns: B-Tree e o “caminho por páginas”

O índice mais comum em bancos relacionais é baseado em B-Tree. Ele organiza chaves em uma estrutura
hierárquica com páginas (blocos) para minimizar leituras de disco/IO.

O fluxo típico para uma consulta de igualdade ou faixa é:

  • o banco entra na raiz da árvore;
  • compara a chave e desce para o nó/página correta;
  • repete até chegar ao nível das folhas;
  • nas folhas, encontra as entradas com a chave e descobre os locais das linhas;
  • por fim, acessa a tabela (ou pelo menos as páginas necessárias) para retornar os campos.
Por que isso é rápido: em uma B-Tree bem preenchida, a busca faz poucas “descidas” pela altura
da árvore. Cada descida evita varrer milhares/milhões de linhas.

Outro ponto: índices por colunas diferentes mudam a forma como as chaves são “ordenadas” dentro do índice,
afetando diretamente operações de igualdade, intervalo e ORDER BY.

4 Custos e armadilhas: manutenção, duplicidade, cobertura e ordem das colunas

Índice melhora leitura, mas cobra caro na escrita e no consumo de recursos. Os custos principais são:

  • Espaço em disco: o índice pode ser grande (principalmente em colunas largas).
  • Escrita mais lenta: INSERT/UPDATE/DELETE precisam atualizar o índice.
  • Fragmentação e concorrência: índices recebem muitas mudanças e podem exigir ajustes/rebalanceamentos.

Armadilha comum: índice para “toda” coluna

Colocar índices indiscriminadamente raramente melhora o sistema como um todo.
O que você quer é reduzir leituras com base no padrão real de consultas (filtros, junções e ordenação).

Ordem das colunas em índices compostos

Em índices compostos, a ordem importa porque a estrutura é ordenada pela primeira coluna, depois pela segunda, e assim por
diante. Isso afeta diretamente quais filtros conseguem aproveitar o índice.

Cobertura (quando aplicável): alguns bancos conseguem retornar a consulta apenas com o índice
(evitando ir à tabela) se as colunas necessárias estiverem presentes no índice. Isso pode reduzir “lookups” na tabela.

5 Exemplo prático: criar índice, conferir plano e entender o ganho

Um jeito confiável de validar índice é: criar (ou ajustar) o índice alinhado ao filtro/junção e comparar o plano antes e depois.
Abaixo vai um exemplo genérico em SQL (a sintaxe pode variar entre bancos).

-- Tabela exemplo:
-- orders(id, customer_id, status, created_at, total)

-- Consulta frequente: filtra por customer_id e status, ordena por created_at
SELECT id, created_at, total
FROM orders
WHERE customer_id = 123
  AND status = 'PAID'
ORDER BY created_at DESC
LIMIT 50;

-- 1) Índice alinhado ao padrão do WHERE + ORDER BY
-- (ordem das colunas importa)
CREATE INDEX idx_orders_customer_status_created_at
ON orders (customer_id, status, created_at DESC);

-- 2) Ver o plano de execução (varia conforme o SGBD)
-- Exemplo genérico:
EXPLAIN (ANALYZE, BUFFERS)
SELECT id, created_at, total
FROM orders
WHERE customer_id = 123
  AND status = 'PAID'
ORDER BY created_at DESC
LIMIT 50;

-- 3) Comparar:
-- - se antes fazia full scan (ou muito trabalho na tabela)
-- - depois passa a fazer index scan/seek
-- - e tende a reduzir leituras e tempo

Interpretação esperada: você quer que o plano use o índice para localizar as linhas do conjunto reduzido e, idealmente,
evite leituras desnecessárias (ou “lookups” excessivos).

Quer aprofundar e aplicar no seu projeto?

Leia outros posts aqui no yurideveloper.com e deixe seu banco mais rápido com decisões embasadas (índices, planos e modelagem).



Ver mais posts



“`