Mistake #54 : The N+1 Problem

リンゴを1個ずつ
レジに並ぶ人

「100個ください」とまとめて言えばいいのに、
1個取ってはお会計、また1個取ってはお会計。
そんな買い方をしていたら、お店(サーバー)は大渋滞します。

🐢 パフォーマンス劣化診断
  • 開発環境(データ10件)ではサクサク動いている
  • 本番環境で一覧画面を開くと、表示されるまで10秒以上かかる
  • ループ処理(for / each)の中でデータベースを呼び出している
  • 「Eager Loading(イーガーローディング)」という言葉を知らない
⚠️ 警告:これは「セルフDDoS攻撃」です。
あなた自身が書いたプログラムが、サーバーを攻撃してダウンさせようとしています。

01. 悪意なき攻撃コード

SELECT * FROM users; -- (1回目: リスト取得)
SELECT * FROM depts WHERE id=1; -- (2回目)
SELECT * FROM depts WHERE id=2; -- (3回目)
SELECT * FROM depts WHERE id=3; -- (4回目)
SELECT * FROM depts WHERE id=4; -- (5回目)
SELECT * FROM depts WHERE id=5; -- (6回目)

「ユーザー一覧を表示し、それぞれの所属部署名も出す」。
これをプログラムで無邪気に書くと、
「①全ユーザーを取得するSQL(1回)」と、
「②ユーザーの数だけ部署情報を取得するSQL(N回)」が発行されます。
合計N+1回。
もしユーザーが1000人いれば、画面を1回表示するだけで1001回もデータベースに接続します。
10人が同時に見たら? 1万回の通信が発生し、サーバーは死にます。

データ量が増えても遅くならない。
それが「プロのコード」だ。

02. 魔法の技術「Eager Loading」

解決策は単純です。「買い物リスト」を作ってからレジに行くことです。
「Eager Loading(イーガーローディング=先読み)」という技術を使えば、
「②全ユーザーの部署情報を、IDを指定してまとめて持ってくるSQL」を1回投げるだけで済みます。
SQLの発行回数は、1001回からたったの2回に減ります。
パフォーマンスは500倍になります。
これを「知っているか、知らないか」。それだけでエンジニアの価値が決まります。

03. スロークエリを狩る

システム稼働後も油断はできません。
「スロークエリログ(遅いSQLの記録)」を定期的にチェックし、
時間がかかっている処理をピンポイントで改善する。
この地道なチューニング作業を行わない限り、システムは日々肥大化するデータに押しつぶされ、いつか必ず停止します。

執筆:パフォーマンス・チューニングチーム

ミリ秒単位の高速化に命を燃やすDBエンジニア集団。
インデックス設計からクエリ最適化まで、システムの「血管の詰まり」を完全に取り除きます。