IT-Q

一覧ページの表示が重いと報告されました。Eloquent を使っています。最初に何をしますか。

まず発行クエリ数を数えます。件数に比例して増えていれば N+1、増えないなら次にインデックスを疑います。当てずっぽうに with() を足す前に測る、が面談で見られている順序です。

面接官が見ているのはN+1 に自力でたどり着けるか。「重い」を具体的な原因に分解できるか。

よくある答えと、面談でどう見られるか

  • 発行されているクエリの本数を計測する
    これが最初の一手です。「重い」の原因はクエリ本数・1本あたりの遅さ・取得件数のどれかなので、まず切り分ける。件数に比例してクエリが増えていれば N+1 です。
  • インデックスが足りないと考え、貼ってみる
    悪くない発想ですが順番が逆です。インデックスは「1本のクエリが遅い」場合に効く対策で、「クエリが何百本も出ている」場合には効きません。今回は N+1 でした。
  • とりあえず with() を付けてリレーションを事前ロードする
    結果的に当たることはありますが、面談では「なぜ with() で直ると思ったのか」を必ず突かれます。原因を確認せずに手が出るのは、N+1 を説明できない状態のサインと見られます。
  • ページ全体にキャッシュを入れて速く見せる
    原因を特定せずに症状を隠す対応です。データが更新されない・破棄漏れという別の障害を新しく作ります。「なぜ遅いか」から始めてください。

面接官は何を見ているか

  • 発行されているクエリ本数を確認する、と言えた
  • N+1(ループ内でリレーションを引く)に触れた
  • 推測ではなく計測(Debugbar / Telescope / DB::listen)から入ると言えた

模範解答

まず何本クエリが出ているかを見ます。Laravel Debugbar や Telescope、なければ DB::listen でログに落とします。一覧ページで件数に比例してクエリが増えていれば N+1 です。それが無ければ、次にインデックスの有無と、そもそも取得件数が多すぎないかを見ます。「重い」の原因はクエリ本数・1本の遅さ・件数のどれかなので、まずどれかを切り分けます。

ここからどう深掘りされるか

この問いに答えられた場合、面談は次の質問に進みます。

観点をすべて押さえられた場合
N+1 でした。どう直しますか。