IT-Q

N+1 でした。どう直しますか。

with() でリレーションを事前ロードします。ループ内で都度引いていた 1+N 本が、親1本と子の whereIn 1本の計2本にまとまります。再発防止は preventLazyLoading です。

面接官が見ているのはwith() を知っているか。単なる暗記か、仕組みを理解しているか。

これは「一覧ページの表示が重いと報告されました。Eloquent を使っています。最初に何をしますか。」への追撃質問です。

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

  • with() でリレーションを事前ロードする
    1+N 本が2本になります。開発環境では Model::preventLazyLoading() を有効にして、遅延ロード時に例外が飛ぶようにしておくと再発を防げます。
  • ループの中で使っているリレーションを毎回 fresh() で取り直す
    かえってクエリが増えます。N+1 を悪化させる方向です。
  • 一覧の取得件数を減らしてページングする
    症状は軽くなりますが、1ページあたりで見れば N+1 は残ったままです。件数を増やせばまた顕在化します。
  • DB のコネクションプールを増やす
    本数の問題を並列度で殴る発想です。DB 側の負荷は減りません。

面接官は何を見ているか

  • with() による Eager Loading を挙げた
  • 「クエリが 1+N 本から 2 本になる」と仕組みで説明できた
  • 再発防止(preventLazyLoading 等)に触れた

模範解答

リレーションを with() で事前ロードします。ループ内で都度引いていたものが、親の取得1本+子の whereIn 1本の計2本にまとまります。再発防止には Model::preventLazyLoading() を開発環境で有効にして、遅延ロードが起きたら例外を投げるようにしておくのが有効です。

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

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