IT-Q

10万件を処理するとき、Eloquent の何がコストになりますか。

1件ごとの Model 生成コストと、get() で全件をメモリへ載せるコストの2つです。chunk() で分割するか、cursor() や lazy() で1件ずつ流します。使い分けに条件があります。

面接官が見ているのは「なんとなく遅い」ではなく理由を言えるか。

これは「Eloquent を使わず Query Builder や生SQLを選ぶのが妥当なのはどれですか。」への追撃質問です。

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

  • 1件ごとのモデルインスタンス生成コストと、get() で全件をメモリに載せるコスト
    その通りです。対処は chunk() で分割するか、cursor() / lazy() で1件ずつ流すか。cursor はメモリ一定ですが速度は出ません。
  • SQL の組み立てに時間がかかること
    組み立て自体は誤差です。効くのはオブジェクト生成とメモリです。
  • Eloquent は必ず JOIN を発行するのでクエリが重くなること
    必ず JOIN するわけではありません。
  • バリデーションが毎回走ること
    Eloquent は保存時にバリデーションを走らせません。

面接官は何を見ているか

  • モデルインスタンス生成のコストを挙げた
  • 全件をメモリに載せる問題に触れた
  • chunk / cursor / lazy による対処を挙げた

模範解答

2つあります。1件ごとに Model オブジェクトを生成するCPUとメモリのコストと、get() で全件を一度にメモリへ載せるコストです。対処は chunk() で分割するか、cursor() / lazy() で1件ずつ流すか。cursor() は PHP のジェネレータを使い、発行するクエリは1本のまま、メモリに載せるモデルを常に1件だけに保ちます。ただし2つ制約があります。リレーションを eager load できないこと。それと、PDO が生の結果を内部バッファに溜めるので、件数が極端に多いと結局メモリを使い切ること。リレーションが要る場合や件数が読めない場合は lazy() を選びます。