1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Laravel 12】N+1問題は「未然に防ぐ」が鉄則。preventLazyLoading()の重要性とwith()の基本

1
Last updated at Posted at 2026-04-08

この記事でわかること

  • N+1問題は「気づかないうちに」パフォーマンスとUXを破壊する
  • 開発環境で Model::preventLazyLoading() を有効化し、N+1をシステム的に検知・ブロックすべき
  • リレーション先のデータが必要な場合は、必ず with()(Eager Loading)を使う

はじめに

Laravelを使った開発で、誰もが一度は直面する(あるいは気づかずに放置してしまう)のが 「N+1問題」 です。
ローカル環境ではデータ量が少ないためサクサク動いていても、本番環境にデプロイしてデータが増えた途端に「画面の表示が異常に遅い…」という事態を引き起こします。

画面の表示速度の低下は、ユーザーの離脱率を高め、結果的にビジネス上の機会損失(UXの悪化)に直結します。
この記事では、Laravel 12での実装において「N+1問題を未然に防ぐための仕組み作り」と、その解決策についてまとめました。


1. 気づかぬうちに潜む「N+1問題」とは?

N+1問題とは、データベースからデータを取得する際、「親モデルを取得する1回のクエリ」+「子モデルを取得するN回のクエリ」 が発行されてしまうパフォーマンスのボトルネックです。

例えば、「ブログ記事(Post)」とその「作成者(User)」を表示する場合を考えます。

// ❌ 悪い例(Lazy LoadingによるN+1発生)
$posts = Post::all(); // ① 記事を全件取得するクエリ(1回)

foreach ($posts as $post) {
    // ② ループのたびに、その記事の作成者を取得するクエリが走る(N回)
    echo $post->user->name; 
}

もし記事が100件あれば、合計101回のSQLが発行されてしまいます。これがN+1問題です。


2. 仕組みで未然に防ぐ:preventLazyLoading() の重要性

N+1問題の厄介なところは、コードとしてはエラーにならず、正しく動いてしまうことです。そのため、コードレビューや手動のテストで見逃されがちです。

そこで絶対に活用したいのが、Laravelに備わっている 遅延読み込み(Lazy Loading)の無効化機能 です。

設定方法

App\Providers\AppServiceProviderboot メソッドに以下を追記します。

use Illuminate\Database\Eloquent\Model;

public function boot(): void
{
    // 本番環境以外(ローカルやテスト環境)でのみ、遅延読み込みを禁止する
    Model::preventLazyLoading(! app()->isProduction());
}

なぜこれが重要なのか?

この1行を追加するだけで、開発中にN+1問題を引き起こすコード(前述の悪い例など)が実行された瞬間、即座に例外(Exception)を投げて画面をエラーにしてくれます

「後で気づいて直す」のではなく、「開発環境の時点で絶対にN+1を許さない仕組み」を作ることが、堅牢でUXを損なわないアプリケーション作りの鉄則です。


3. 具体的な解決策:with() による Eager Loading

preventLazyLoading() でN+1を検知できたら、正しいクエリに修正します。
解決策はシンプルで、with() メソッドを使って Eager Loading(事前割り当て) を行うだけです。

// ⭕️ 良い例(Eager Loading)
// 記事を取得する際に、関連するユーザー情報も一緒に取得しておく
$posts = Post::with('user')->get(); 

foreach ($posts as $post) {
    // すでに取得済みなので、ここではSQLは発行されない!
    echo $post->user->name; 
}

これにより、発行されるSQLは「記事を取得するクエリ(1回)」と「そこに関連するユーザーをIN句でまとめて取得するクエリ(1回)」の合計2回に劇的に削減されます。


まとめ

システムをレガシーからモダンへ移行していく中で、「動けばいい」から一歩進んで「パフォーマンスとUXを担保できる設計」を意識することは非常に重要です。

  • 開発環境では Model::preventLazyLoading(!app()->isProduction()); を必ず設定し、検知を自動化する。
  • リレーションを取得する際は with() を使ってEager Loadingを徹底する。

これらのベストプラクティスを仕組みとして取り入れ、今後の実装でも積極的に活用していきたいと思います!

1
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?