DevGuideTK
← Trilha Backend

Índices

A estrutura que faz uma consulta cair de segundos para milissegundos, e o que ela custa na escrita.

O problema: procurar sem índice

Imagine uma tabela com dois milhões de pedidos e a consulta mais comum do sistema: os pedidos de um cliente.

SELECT * FROM pedidos WHERE cliente_id = 4242;

Sem nenhuma ajuda, o banco só tem uma forma de responder: ler as dois milhões de linhas, uma por uma, e separar as 22 que pertencem ao cliente. Isso se chama varredura sequencial (sequential scan). Num teste com essa tabela no PostgreSQL, ela levou 77 milissegundos.

Parece pouco, mas o tempo cresce junto com a tabela, e a consulta roda a cada vez que alguém abre a tela de pedidos. Com dez vezes mais dados ou cem usuários ao mesmo tempo, o banco passa o dia lendo linhas que não interessam a ninguém.

A ideia do índice

Um índice resolve o problema do mesmo jeito que o índice remissivo de um livro. Em vez de folhear todas as páginas atrás de um assunto, você vai ao final do livro, encontra o termo em ordem alfabética e lê os números das páginas.

O índice de banco é uma cópia de uma ou mais colunas, mantida em ordem, em que cada valor aponta para a linha correspondente na tabela.

CREATE INDEX idx_pedidos_cliente ON pedidos (cliente_id);

Com o índice criado, a mesma consulta levou 0,12 milissegundo, mais de 600 vezes mais rápida. O banco foi direto aos 22 registros.

Como o índice encontra o valor

O tipo mais comum de índice é a árvore B (B-tree). Ela organiza os valores em níveis, como um índice de livro com subdivisões:

                    [ 30000 | 60000 ]
                   /        |        \
    [ 10000 | 20000 ]  [ 40000 | 50000 ]  [ 70000 | 80000 | 90000 ]
       /    |    \          ...                     ...
   folhas com os valores em ordem, cada um apontando para a linha

Cada nível descarta a maior parte dos valores. Com dois milhões de linhas, a árvore tem só três ou quatro níveis. Chegar a qualquer valor custa três ou quatro leituras, em vez de dois milhões. Quando a tabela dobra de tamanho, a árvore ganha no máximo um nível.

Como as folhas estão em ordem, a árvore B também atende:

  • buscas por intervalo: WHERE criado_em > '2026-01-01';
  • ordenação: ORDER BY criado_em DESC, sem precisar ordenar depois;
  • prefixos de texto: WHERE email LIKE 'marina%', com a configuração de ordenação adequada.

O que o índice custa

O índice não é de graça. Toda gravação na tabela também precisa atualizar cada índice dela.

CustoO que acontece
Escrita mais lentaCada INSERT, UPDATE de coluna indexada e DELETE mexe na tabela e em todos os índices
Espaço em discoNo teste, a tabela tinha 174 MB; um índice de uma coluna ocupou 15 MB e um índice sobre um texto, 95 MB
MemóriaÍndices consultados com frequência precisam caber em memória para serem rápidos

No mesmo teste, inserir 500 mil linhas levou 1 segundo numa tabela só com a chave primária e 5,4 segundos numa tabela com a chave primária e mais cinco índices.

Por isso a regra não é "indexe tudo". É indexar o que as consultas frequentes usam, e nada além disso.

Seletividade: quando o índice ajuda

Um índice só vale a pena quando a consulta separa poucas linhas do total. Essa proporção se chama seletividade.

ConsultaLinhas encontradasÍndice ajuda?
WHERE cliente_id = 424222 de 2 milhõesMuito
WHERE email = '...'1 de 2 milhõesMuito
WHERE status = 'pago'400 mil de 2 milhões (20%)Pouco ou nada

No caso do status, o banco precisaria saltar para 400 mil posições espalhadas pela tabela. Ler tudo em sequência acaba custando quase o mesmo, e às vezes menos. O planejador do banco faz essa conta sozinho e pode decidir ignorar um índice que existe.

Índices com mais de uma coluna

Um índice pode ter várias colunas. A ordem delas importa, porque os valores ficam ordenados pela primeira coluna, depois pela segunda dentro da primeira, e assim por diante, como uma lista telefônica ordenada por sobrenome e depois por nome.

CREATE INDEX idx_pedidos_cliente_data ON pedidos (cliente_id, criado_em DESC);

Esse índice atende a tela "últimos pedidos do cliente" por inteiro: encontra o cliente e já percorre os pedidos dele em ordem de data, parando nos 20 primeiros. Mas ele não serve para buscar pedidos só pela data, sem o cliente, assim como a lista telefônica não ajuda a achar todo mundo chamado Marina. No teste, a consulta só por data continuou lendo a tabela inteira mesmo com esse índice.

Por que isso importa quando a IA escreve o código

Um assistente escreve a consulta certa e quase nunca cria o índice que ela precisa, porque o índice mora na migração, longe do código que faz a busca. Os problemas aparecem com volume:

  • A consulta funciona em desenvolvimento, com cem linhas, e trava em produção, com milhões.
  • A busca usa lower(email) ou LIKE '%texto%', e o índice existente deixa de ser usado.
  • O índice composto é criado com as colunas na ordem errada para a consulta.
  • Cada sugestão de otimização acrescenta mais um índice, e as gravações ficam lentas.

O próximo nível compara os tipos de índice e mostra como decidir o que indexar.

Prompts para aprofundar

Ao abrir no ChatGPT ou no Claude, o prompt é enviado ao serviço escolhido pela URL e também fica copiado na sua área de transferência.

  • Índices em cinco minutos

    Explique em no máximo cinco minutos de leitura o que é um índice de banco de dados, para alguém que programa mas nunca otimizou uma consulta.
    
    Cubra só o essencial: o que acontece numa consulta sem índice, como o índice encontra os dados, o que ele custa na escrita e por que nem toda coluna deve ter índice.
    
    Use a analogia do índice remissivo de um livro. No final, me faça três perguntas curtas para eu verificar se entendi, e corrija as minhas respostas.
  • Por dentro de uma árvore B

    Quero entender como um índice de árvore B funciona por dentro.
    
    Aja como um mentor de bancos de dados. Pergunte primeiro qual é a minha experiência com SQL.
    
    Conduza assim, uma etapa por vez, com uma pergunta de verificação ao fim de cada uma:
    1. O que o banco faz para responder uma consulta numa tabela sem índice, e por que o tempo cresce com a tabela.
    2. A estrutura de uma árvore B: nós, níveis e folhas, com um desenho em texto. Mostre quantos níveis uma tabela de dez milhões de linhas teria.
    3. O caminho de uma busca por igualdade, de uma busca por intervalo e de uma consulta com ORDER BY e LIMIT.
    4. O que acontece com o índice a cada INSERT, UPDATE e DELETE.
    
    No final, peça que eu explique com minhas palavras por que um índice acelera a leitura e encarece a escrita, e corrija o que estiver impreciso.
  • Seletividade e as decisões do planejador

    Quero entender por que o banco às vezes ignora um índice que existe.
    
    Explique:
    1. O que é seletividade, com exemplos de colunas de alta e de baixa seletividade.
    2. Como o planejador estima quantas linhas uma consulta vai retornar, e de onde vêm essas estatísticas.
    3. Por que ler a tabela inteira pode ser mais barato do que usar o índice quando a consulta retorna muitas linhas.
    4. O que acontece quando as estatísticas estão desatualizadas.
    
    Depois me apresente cinco consultas sobre uma tabela de pedidos com dois milhões de linhas, informando quantas linhas cada uma retorna, e pergunte se o banco deve usar o índice em cada caso. Corrija as minhas respostas.
  • Índices compostos e a ordem das colunas

    Quero entender de vez como funcionam os índices com mais de uma coluna.
    
    Use a analogia de uma lista telefônica ordenada por sobrenome e depois por nome, e explique por que a ordem das colunas decide quais consultas o índice atende.
    
    Depois, crie um índice composto de exemplo numa tabela de pedidos e me apresente oito consultas, uma por vez, perguntando se o índice atende cada uma, total ou parcialmente. Inclua consultas com igualdade, com intervalo, com ORDER BY, com IN, com a segunda coluna sozinha e com OR.
    
    Corrija cada resposta e, no final, me dê a regra prática para ordenar as colunas de um índice composto.