Appearance
N+1 問題 ― 100件表示で何クエリ走る?
KeyTerms
| 用語 | 意味 | なぜ重要か |
|---|---|---|
| N+1 問題 | メインクエリ1回 + 関連データN回で計N+1回のクエリが発生する問題 | 大量データで応答時間が指数関数的に悪化する |
| Eager Loading | with()で関連データを事前に一括取得する最適化手法 | 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に聞く前に、自分の頭で考えてみましょう。
テキストを入力すると有効になります