Objetivos comuns de performance em banco de dados
Quando alguém diz “a consulta está lenta”, vale traduzir isso em objetivos mensuráveis. Em bancos de dados, três objetivos aparecem com frequência:
- Tempo de resposta (latência): quanto tempo uma consulta específica leva para retornar o resultado. Ex.: “listar os pedidos do cliente em até 200 ms”.
- Throughput (vazão): quantas operações o sistema consegue completar por unidade de tempo. Ex.: “processar 2.000 consultas por segundo”.
- Previsibilidade: estabilidade do tempo de resposta. Ex.: “95% das consultas abaixo de 300 ms”, evitando picos (cauda longa) que afetam a experiência.
Esses objetivos se conectam diretamente a como o banco lê dados do armazenamento: quanto mais trabalho de leitura e varredura, maior a latência, menor a vazão e pior a previsibilidade.
Como consultas acessam dados: páginas/blocos e o custo de I/O
Internamente, o banco não “lê uma linha” do disco/SSD; ele lê páginas (também chamadas de blocos), que são pedaços fixos de dados (por exemplo, 8 KB, 16 KB etc., dependendo do sistema). Uma página pode conter várias linhas. Isso cria uma consequência importante: mesmo que você precise de poucas linhas, pode acabar lendo muitas páginas até encontrá-las.
Pense em um arquivo físico com fichas: você não pega uma ficha isolada; você puxa uma gaveta inteira (a página) e procura dentro. Se a ficha desejada estiver espalhada por várias gavetas, você abre várias gavetas (I/O).
Leitura sequencial (varredura) vs. acesso por busca
Existem dois padrões comuns de acesso:
- Ouça o áudio com a tela desligada
- Ganhe Certificado após a conclusão
- + de 5000 cursos para você explorar!
Baixar o aplicativo
- Leitura sequencial / varredura (scan): o banco percorre muitas páginas em sequência para avaliar um filtro. É eficiente quando precisa de grande parte da tabela, mas caro quando você quer poucos registros.
- Acesso por busca (seek/lookup): o banco usa uma estrutura para ir mais direto às páginas relevantes, reduzindo o número de páginas lidas.
Em geral, “lentidão” em consultas de filtro/ordenação costuma estar ligada a muito I/O (muitas páginas lidas) e/ou muita varredura (scan amplo), especialmente quando o resultado final é pequeno.
Por que índices existem: reduzir dados lidos e encurtar o caminho
Um índice é uma estrutura que organiza valores de uma ou mais colunas para permitir que o banco encontre registros com menos leitura. A ideia central é:
- Reduzir o volume de dados lidos: em vez de ler a tabela inteira, o banco lê uma parte menor (o índice) e só visita as páginas de dados necessárias.
- Encurtar o caminho até os registros: em vez de “procurar página por página”, o banco segue uma rota mais direta até as chaves/linhas que atendem ao filtro.
Analogia controlada: imagine uma lista telefônica (índice) que aponta rapidamente para a página onde o nome aparece. Sem a lista organizada, você folhearia página por página (scan). Com a lista, você pula para perto do alvo (busca), abrindo menos “gavetas”.
O que o índice “compra” e o que ele “cobra”
Índices costumam melhorar leituras seletivas, mas têm custos:
- Espaço: ocupam armazenamento e cache.
- Escrita mais cara: INSERT/UPDATE/DELETE precisam manter o índice atualizado.
- Planejamento: muitos índices podem confundir o otimizador e aumentar o tempo de manutenção.
Conectando sintoma a causa: exemplos simples (filtros e ordenações)
Vamos usar uma tabela hipotética pedidos:
pedidos(id, cliente_id, status, criado_em, total)Exemplo 1 — Filtro seletivo: poucos registros retornados
Consulta:
SELECT id, total, criado_em FROM pedidos WHERE cliente_id = 42;Sintoma: demora mesmo retornando poucas linhas.
Causa provável: sem índice em cliente_id, o banco pode fazer varredura na tabela para checar cada linha, lendo muitas páginas até achar as do cliente 42.
Como o índice ajuda: um índice em cliente_id permite localizar rapidamente as entradas do cliente e visitar apenas as páginas relevantes.
Exemplo 2 — Filtro pouco seletivo: muitos registros retornados
Consulta:
SELECT * FROM pedidos WHERE status = 'PENDENTE';Sintoma: consulta pesada e com grande volume de dados.
Causa provável: se uma grande parte da tabela está com status = 'PENDENTE', mesmo com índice o banco pode decidir que é melhor varrer (scan) porque acabaria lendo muitas páginas de qualquer forma.
Interpretação prática: índice não é “mágico”; ele tende a ajudar quando o filtro reduz bastante o conjunto de linhas (alta seletividade).
Exemplo 3 — Ordenação: quando o ORDER BY vira gargalo
Consulta:
SELECT id, total FROM pedidos WHERE cliente_id = 42 ORDER BY criado_em DESC;Sintoma: a consulta filtra rápido, mas fica lenta ao ordenar.
Causa provável: o banco encontra as linhas do cliente, mas precisa ordenar o resultado (operações de sort) porque não consegue ler já na ordem desejada.
Como o índice ajuda: um índice composto que combine filtro e ordenação pode permitir que o banco leia os registros já na ordem, reduzindo ou eliminando o sort.
Exemplo de ideia (conceitual): índice em (cliente_id, criado_em) pode ajudar a filtrar por cliente_id e entregar em ordem de criado_em.
Exemplo 4 — Paginação: “pegar a próxima página” pode custar caro
Consulta:
SELECT id, criado_em FROM pedidos ORDER BY criado_em DESC OFFSET 10000 LIMIT 20;Sintoma: páginas iniciais rápidas, páginas mais profundas muito lentas.
Causa provável: o banco precisa percorrer/descartar muitas linhas até chegar no offset, lendo muitas páginas e fazendo trabalho que não vira resultado.
Como o índice pode ajudar: um índice em criado_em pode reduzir custo de ordenação, mas o OFFSET alto ainda força “andar” muito. (Aqui, o problema é menos “falta de índice” e mais “forma de paginação”, mas o índice costuma ser parte do diagnóstico.)
Passo a passo prático: diagnosticando lentidão ligada a varredura e I/O
Passo 1 — Identifique o padrão da consulta
- Tem
WHEREcom igualdade (=) ou faixa (>=,BETWEEN)? - Tem
ORDER BY? - Retorna poucas linhas ou muitas?
- Usa paginação (
LIMIT/OFFSET)?
Passo 2 — Pergunte: “o banco está varrendo demais?”
Sem entrar em ferramentas específicas, o raciocínio é:
- Se retorna poucas linhas, mas demora muito, suspeite de scan amplo (muitas páginas lidas para achar poucas linhas).
- Se ordena e demora, suspeite de sort por falta de caminho já ordenado.
- Se há picos de tempo, suspeite de cache misses (precisou buscar mais páginas no armazenamento) e de variações no plano.
Passo 3 — Relacione o filtro/ordenação com colunas candidatas a índice
- Filtros frequentes em colunas com boa seletividade tendem a ser bons candidatos.
- Combinações comuns de filtro + ordenação podem pedir índice composto.
- Se a consulta seleciona poucas colunas, um índice que “cubra” a consulta pode reduzir visitas à tabela (dependendo do banco).
Passo 4 — Avalie o custo de escrita e manutenção
- Tabela muito atualizada (muitos INSERT/UPDATE/DELETE)? Índices demais podem piorar throughput de escrita.
- Coluna com valores que mudam muito? Atualizações podem gerar mais trabalho de manutenção.
- Índices redundantes (muito parecidos) podem desperdiçar espaço e cache.
Mapa mental de decisões: quando índices ajudam e quando atrapalham
| Situação | Índice tende a ajudar quando… | Índice pode atrapalhar quando… |
|---|---|---|
| Filtro (WHERE) | O filtro reduz bastante as linhas (alta seletividade); você busca um subconjunto pequeno com frequência. | O filtro retorna grande parte da tabela; o banco ainda precisará ler muitas páginas (scan pode ser melhor). |
| Ordenação (ORDER BY) | A ordenação é frequente e pode ser atendida pela ordem do índice, reduzindo sort. | A ordenação muda muito (muitas colunas/ordens diferentes), levando a muitos índices ou a índices pouco usados. |
| Consultas com LIMIT pequeno | Você quer “os primeiros N” em uma ordem específica; índice pode permitir parar cedo (early stop). | Com OFFSET alto, mesmo com índice pode haver muito trabalho para “pular” registros. |
| Leituras vs escritas | O sistema é mais leitura (read-heavy) e precisa de baixa latência em consultas críticas. | O sistema é mais escrita (write-heavy); cada índice extra aumenta custo de INSERT/UPDATE/DELETE. |
| Colunas usadas em JOIN | Chaves de junção são usadas frequentemente e restringem bem o conjunto de linhas. | Junções em colunas pouco seletivas ou com baixa utilidade prática; índice vira custo sem ganho. |
| Espaço e cache | O índice cabe bem em memória/cache e evita leituras de páginas de dados. | Muitos índices competem por cache, piorando previsibilidade e aumentando I/O em picos. |