A Importância do Eager Loading no Laravel: Evitando o Problema N+1

O eager loading é uma técnica essencial no Laravel para otimizar o desempenho de aplicações, evitando o problema de consultas N+1. Este artigo explica como o eager loading funciona, os impactos de não utilizá-lo e como configurar o Laravel para prevenir problemas relacionados ao lazy loading, incluindo o uso do recurso de carregamento automático de relacionamentos.

Publicado em: 14, abril 2025

Imagem do automatically Eager Load Relationship para corrigir globalmente qualquer problema de query N+1 que possa ter no codigo

No desenvolvimento de aplicações web, a eficiência na comunicação com o banco de dados é crucial para garantir uma boa experiência ao usuário. No Laravel, o eager loading é uma prática poderosa para otimizar consultas e evitar problemas comuns, como o temido N+1 query problem. Neste artigo, exploraremos o que é o eager loading, por que ele é importante e como configurá-lo corretamente para melhorar a performance da sua aplicação.

O que é o Problema N+1?

O problema N+1 ocorre quando uma aplicação realiza consultas adicionais ao banco de dados para cada item em um conjunto de dados, em vez de carregar todos os dados necessários de uma só vez. Vamos ilustrar com um exemplo:

Imagine que você tem um modelo User que possui um relacionamento hasMany com Post, e cada Post tem um relacionamento hasMany com Comment. Se você buscar todos os usuários e iterar sobre seus posts e comentários sem eager loading, o código pode parecer assim:

$users = User::all();

foreach ($users as $user) {
    foreach ($user->posts as $post) {
        foreach ($post->comments as $comment) {
            echo $comment->content;
        }
    }
}

Sem eager loading, o Laravel executará:

  • 1 consulta para buscar todos os usuários;
  • N consultas adicionais para buscar os posts de cada usuário (onde N é o número de usuários);
  • M consultas para buscar os comentários de cada post (onde M é o número total de posts).

Se você tiver 100 usuários e cada um tiver 10 posts, isso resultará em 1 + 100 + (100 * 10) = 1.101 consultas! Esse é o problema N+1, que pode degradar significativamente a performance da sua aplicação.

O Papel do Eager Loading

O eager loading resolve esse problema ao carregar os relacionamentos necessários de uma só vez, reduzindo o número de consultas ao banco de dados. No exemplo acima, você pode usar o método with para carregar os relacionamentos antecipadamente:

$users = User::with('posts.comments')->get();

foreach ($users as $user) {
    foreach ($user->posts as $post) {
        foreach ($post->comments as $comment) {
            echo $comment->content;
        }
    }
}

Com o eager loading, o Laravel executará apenas 3 consultas:

  • 1 para buscar os usuários;
  • 1 para buscar todos os posts relacionados aos usuários;
  • 1 para buscar todos os comentários relacionados aos posts.

Isso reduz drasticamente o impacto no banco de dados, melhorando a performance e a escalabilidade da aplicação.

Automatic Eager Loading no Laravel

O Laravel oferece um recurso em fase beta chamado Automatic Eager Loading, que tenta carregar relacionamentos automaticamente quando eles são acessados, mesmo que não tenham sido carregados previamente com with. Para habilitar esse recurso, você pode configurar o método Model::automaticallyEagerLoadRelationships no AppServiceProvider:

use Illuminate\\Database\\Eloquent\\Model;

*/**
 * Bootstrap any application services.
 */*
public function boot(): void
{
    Model::automaticallyEagerLoadRelationships();
}

Com essa configuração, o Laravel detecta quando você tenta acessar um relacionamento não carregado e realiza o carregamento lazy eager automaticamente. Por exemplo, no código inicial sem with, o Laravel carregaria os posts e comentários de forma otimizada quando acessados, evitando consultas redundantes.

Embora esse recurso seja promissor, ele está em beta, e sua funcionalidade pode mudar. Portanto, é recomendável testá-lo cuidadosamente antes de usá-lo em produção.

Prevenindo o Lazy Loading

O lazy loading (carregamento preguiçoso) ocorre quando os relacionamentos são carregados sob demanda, o que pode levar ao problema N+1 se não for gerenciado corretamente. Para evitar isso, o Laravel permite desativar o lazy loading globalmente, garantindo que sua aplicação só carregue relacionamentos explicitamente definidos com with. Você pode configurar isso no AppServiceProvider:

use Illuminate\\Database\\Eloquent\\Model;

*/**
 * Bootstrap any application services.
 */*
public function boot(): void
{
    Model::preventLazyLoading(! $this->app->isProduction());
}

Essa configuração lança uma exceção (LazyLoadingViolationException) sempre que um relacionamento é carregado preguiçosamente em um ambiente de não-produção, ajudando os desenvolvedores a identificar e corrigir problemas antes que cheguem à produção.

Você também pode personalizar o comportamento das violações de lazy loading. Por exemplo, em vez de lançar uma exceção, você pode registrar a tentativa de lazy loading:

Model::handleLazyLoadingViolationUsing(function (Model $model, string $relation) {
    $class = $model::class;
    info("Tentativa de lazy load [{$relation}] no modelo [{$class}].");
});

Benefícios do Eager Loading

Adotar o eager loading traz vários benefícios:

  • Melhor performance: Reduz o número de consultas ao banco de dados, diminuindo a latência.
  • Escalabilidade: Aplicações com menos consultas são mais capazes de lidar com grandes volumes de tráfego.
  • Código mais previsível: Evitar o lazy loading torna o comportamento do banco de dados mais explícito e fácil de depurar.
  • Manutenção facilitada: Identificar problemas de performance, como o N+1, fica mais simples com ferramentas como o preventLazyLoading.

Conclusão

O eager loading é uma ferramenta indispensável para desenvolvedores Laravel que buscam otimizar a performance de suas aplicações. Ao evitar o problema N+1, você garante que sua aplicação seja mais rápida, escalável e fácil de manter. Recursos como o Automatic Eager Loading e o preventLazyLoading oferecem ainda mais controle sobre como os relacionamentos são gerenciados, ajudando a prevenir erros comuns.

Se você ainda não utiliza o eager loading, comece revisando suas consultas Eloquent e aplicando o método with onde necessário. Além disso, considere habilitar o preventLazyLoading em ambientes de desenvolvimento para capturar possíveis problemas antes que afetem seus usuários. Com essas práticas, sua aplicação Laravel estará pronta para oferecer uma experiência de alto desempenho!

/ Autor

Foto do autor do post Lucas Souza (Virgu)

Lucas Souza (Virgu)

{Full-Stack Specialist Engineer}

Mais de 10 anos de experiência com Laravel e sólidos conhecimentos em frameworks front-end, como ReactJS, React Native e Vue JS.
Experiência em Design de Serviço.
No primeiro projeto profissional como júnior, desenvolveu em e-commerce para a maior indústria de equipamentos odontológicos da América Latina. Atualmente, atua como Full Stack Engineer Specialist em uma grande multinacional.
Lidera decisões técnicas e é um suporte fundamental para a equipe de desenvolvimento.