Skip to content

N+1 問題 ― 100件表示で何クエリ走る?

KeyTerms

用語意味なぜ重要か
N+1 問題メインクエリ1回 + 関連データN回で計N+1回のクエリが発生する問題大量データで応答時間が指数関数的に悪化する
Eager Loadingwith()で関連データを事前に一括取得する最適化手法N+1を数回のクエリに削減できる
Lazy Loading必要になった時点で関連データを取得する遅延読み込みデフォルト動作だがN+1を引き起こす
whereHas()リレーションの条件で親データをフィルタリングするメソッド不要なデータ取得を避けられる
DBパフォーマンスクエリ実行回数が倍増すると、1msのクエリが数秒に膨らむこと実運用では致命的な遅さになる

Prerequisite

  • Laravelのリレーション概念: hasMany、belongsTo、belongsToManyなどの関連付けを理解している
  • クエリの実行コスト: クエリ1回にいくつかmsかかることを認識しており、「101回なら100倍遅い」という感覚がある
  • SQLの基本: WHERE句での絞り込みができることを知っている

Phase 1: 観察

Chapter 2.2 で触れた N+1 問題を、より実践的に見ていきます。

php
// ❌ N+1 問題
$friends = Friend::where('bot_id', $botId)->get();  // 1 クエリ

foreach ($friends as $friend) {
    echo $friend->tags->pluck('name');  // ← 100 件なら 100 クエリ
}
// 合計: 101 クエリ
php
// ✅ Eager Loading
$friends = Friend::where('bot_id', $botId)
    ->with('tags')                                   // ← ここで一括取得
    ->get();                                         // 2 クエリ

foreach ($friends as $friend) {
    echo $friend->tags->pluck('name');  // ← メモリから取得(クエリなし)
}
// 合計: 2 クエリ

Phase 2: 判断

AI禁止ゾーン
  • Friend::all() で 1000 件取得し、各友だちのポイント履歴と住所を表示する画面があります。SQL は何回実行 されますか?
  • with(['point_histories', 'addresses']) を追加したら、何回になりますか?
  • N+1 問題は いつ問題になり、いつ問題にならないですか?

AIに聞く前に、自分の頭で考えてみましょう。

テキストを入力すると有効になります