Abílio Azevedo.

N+1 Queries: How to Fix Them

Cover Image for N+1 Queries: How to Fix Them
Abílio Azevedo
Abílio Azevedo

"Consultas N+1 são uma armadilha comum de desempenho ao usar Object-Relational Mappers (ORMs), como o Django ORM e o Prisma, em aplicações web. Este artigo explica o que são consultas N+1, por que elas afetam o desempenho e como corrigi-las na prática em bases de código que usam Django e Prisma.

O que é uma Consulta N+1?

O padrão de “consulta N+1” ocorre quando uma consulta inicial busca uma lista de itens, e em seguida uma nova consulta é executada para cada item a fim de buscar dados relacionados. Isso resulta em um total de N+1 consultas (N sendo o número de itens). Esse padrão ineficiente normalmente aparece quando ORMs carregam objetos relacionados de forma preguiçosa dentro de loops, o que gera várias idas desnecessárias ao banco de dados e torna a aplicação mais lenta.

Exemplo em Django:

for w in ProgramWorkout.objects.all():
    print(w.id, w.program.id)  # Isso dispara uma nova consulta para cada w.program (N+1 consultas)

Aqui, uma consulta busca todos os objetos ProgramWorkout, mas cada acesso ao programa relacionado gera outra consulta, totalizando N+1 consultas.

| Ruim | Bom | | ![Consulta N+1 ](//images.ctfassets.net/bp521nfj3cq3/1kNgS8fLr11gkNppxG2vwz/e9bbbc766c11f649f599b8811af58371/image.png//images.ctfassets.net/bp521nfj3cq3/74WiXLYH2xNvDaeAxCgmUl/f3ad85e94900a63bbadcd62a2e0611a4/image.png no Django: select_related e prefetch_related

O Django fornece duas ferramentas poderosas do ORM para resolver problemas de N+1:

  • select_related: Usa um JOIN SQL para buscar objetos relacionados em uma única consulta. Ideal para relações do tipo ForeignKey e OneToOne.
    ProgramWorkout.objects.select_related('program').all()
    
  • prefetch_related: Executa uma consulta adicional para buscar todos os objetos relacionados de múltiplos itens principais e os une em memória Python. Ideal para relações reversas de ForeignKey e ManyToMany.
    ProgramWorkout.objects.prefetch_related('programworkoutExercise_set').all()
    

Use select_related para relações de valor único (onde cada item tem apenas um objeto relacionado) e prefetch_related para relações de múltiplos valores ou reversas (onde vários objetos compartilham itens relacionados).

Soluções no Prisma para Consultas N+1

Problemas de N+1 similares ocorrem no Prisma ao buscar dados relacionados em consultas separadas. O Prisma oferece diversas maneiras de corrigir isso:

  • Use include para fazer carregamento antecipado (eager loading) dos campos relacionados em uma ou poucas consultas.
    const workouts = await prisma.programWorkout.findMany({
      include: {
        program: true,
        programWorkoutExercise: true,
      },
    });
    
  • Ative relationLoadStrategy: "join" para realizar junções (joins) no banco de dados internamente, reduzindo o número de consultas para apenas uma.
  • O dataloader interno do Prisma Client agrupa múltiplas consultas findUnique() que ocorrem no mesmo ciclo do event loop em uma única consulta SQL, otimizando padrões de resolvers GraphQL.

Essas técnicas reduzem o tráfego de rede, a carga no banco de dados e melhoram a experiência do usuário, evitando consultas excessivas.

Depurando Consultas N+1

  • Desenvolvedores Django podem usar o Django Debug Toolbar para inspecionar consultas SQL por endpoint e detectar padrões N+1.
  • Ferramentas de monitoramento como o New Relic também podem identificar padrões ineficientes de chamadas ao banco e revelar um alto número de consultas por transação.
  • Usuários do Prisma podem ativar o log de consultas ou usar ferramentas de profiling para detectar consultas excessivas e otimizá-las.

Boas Práticas

  • Sempre analise seu código em busca de riscos de consultas N+1 ao acessar dados relacionados em loops.
  • Use select_related ou prefetch_related no Django, ou include e relationLoadStrategy no Prisma, conforme o tipo de relação do seu modelo de dados.
  • Faça o profiling regular de suas APIs com ferramentas de inspeção de consultas para manter o desempenho ideal.

Referências


Mais posts

Cover Image for Desbloqueando o Crescimento do Negócio com Análises de Produto

Desbloqueando o Crescimento do Negócio com Análises de Produto

Desbloqueie o poder da análise de produto com frameworks práticos, métricas essenciais e as melhores ferramentas, como Google Analytics e Amplitude. Aprenda como insights orientados por dados podem impulsionar o crescimento do produto, melhorar o engajamento dos usuários e alinhar sua equipe para o sucesso — tudo isso com dicas práticas do Curso de Certificação em Análise de Produto.

Abílio Azevedo
Abílio Azevedo
Cover Image for Ganhando tração: Assuma o controle de sua empresa

Ganhando tração: Assuma o controle de sua empresa

Um grande negócio não depende só de visão — depende de execução. O EOS oferece um sistema simples e repetível para transformar ideias em resultados.

Abílio Azevedo
Abílio Azevedo

NewsLetter

Eu enviarei o conteúdo postado aqui no blog. Sem Spam =)

Engenheiro de software experiente, formado em Engenharia Elétrica, com mais de 10 anos de experiência prática na construção de aplicativos móveis, web e back-end robustos e escaláveis em vários projetos, principalmente no setor de fintech. Mobile (React Native), Web (React e Next.JS) e Backend (Node.JS, PHP e DJANGO). Meu objetivo é criar produtos que agreguem valor às pessoas. - © 2025, Abílio Azevedo