章: 第3章: パフォーマンス最適化
一覧ページが遅い原因、N+1になっていませんか?
ユーザー一覧を表示するたびに、各ユーザーの投稿を個別に取得している——そんな実装を見たことはないでしょうか。これがN+1問題です。10件なら10回、1000件なら1001回のクエリが走り、データ量の増加とともに急激にレスポンスが悪化します。
N+1はなぜ起きるのか
アプリケーション側でループを使って関連データを1件ずつ取得するコードは、シンプルに見えて危険です。ORMを使っていても、リレーション取得を明示的に制御しなければN+1になります。根本的な解決はSQL側で一括取得する設計です。
N+1発生パターンと改善策の比較
| パターン | SQL発行回数 | 問題 |
| ループで個別SELECT(N+1) | N+1回(投稿数+1) | データ量増加で線形に悪化 |
| JOIN で一括取得(良い例) | 1回 | 安定したパフォーマンス |
| IN句で一括取得(良い例) | 2回(ID取得+一括取得) | ORMのEager Loadと相性が良い |
チェックポイント: 一覧系APIを書くときは「ループの中でSELECTしていないか」を必ず確認しましょう。スロークエリログや実行回数のモニタリングで、同じパターンのクエリが大量に並んでいたらN+1のサインです。
コードサンプル
SELECT p.id, p.title, u.name
FROM posts p
JOIN users u ON u.id = p.user_id
WHERE p.id IN (101, 102, 103, 104);
まとめ & 次のステップ
- N+1はアプリ側ループでの個別取得が原因で、データ量増加で急激に遅くなります
- 一覧APIはまずJOINやIN句で一括取得できないか設計段階で検討しましょう
- EXPLAINで実行回数と行数を確認し、改善前後を比較して記録します
- ORMを使う場合もEager Loadの設定を明示するクセをつけましょう
- スロークエリログで同一パターンの大量発行を早期に発見できます
次回は クエリチューニングの手順 を学びます。「計測→仮説→検証」の手順を体系化し、再現性のある改善サイクルを回せるようになりましょう。