Pular para conteúdo

Otimização de Consultas e o Problema N+1

Otimização começa por evidências: logs lentos, traces, contagem, planos e dados representativos. Intuição sobre objetos não revela índices, linhas examinadas, transferência, locks ou pressão no banco.

Reconhecendo N+1

N+1 ocorre quando uma consulta carrega pais e outra consulta é executada para os dados relacionados de cada pai. Costuma se esconder em associações lazy, serialização, mapeamento ou renderização.

select orders ...             -- 1 query
select items where order=?    -- repeated N times

Conte statements em teste de integração ou trace. Dados pequenos podem ocultar a latência enquanto a quantidade ainda cresce linearmente.

Estratégia de busca por caso de uso

  • fetch join carrega relacionamento limitado em uma consulta;
  • entity graph explicita associações;
  • projeção recupera apenas campos necessários;
  • batch ou subselect reduz viagens mantendo lazy loading;
  • consulta agregada calcula resumos sem entidades.

Eager generalizado apenas move o problema. Vários relacionamentos to-many multiplicam linhas e memória. Fetch join de coleção interage mal com paginação; em geral, pagine IDs e busque detalhes depois.

Índices e planos

O índice deve combinar predicados seletivos e ordem útil, mas custa escrita e armazenamento. Inspecione o plano real com parâmetros realistas. Evite funções em colunas indexadas sem índice de expressão adequado.

Buscar menos linhas e colunas é mais robusto que esconder desperdício com cache. Reduza também o escopo transacional.

Proteção contra regressões

  • imponha teto de consultas em casos críticos;
  • teste linhas suficientes para expor multiplicação;
  • inspecione SQL e parâmetros;
  • meça cardinalidades e paginação profunda;
  • separe tempo do banco e do mapeamento;
  • reveja planos após mudanças de esquema ou distribuição.

Consulte as orientações de fetching do Hibernate.