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() を選びます。