たまに SQL で取得した ID を使って foreach ループを組んで更に新しいカラムを取得するプログラムを見かけますが、ご存知の通り、SQL の多量発行はコストの高い操作です。
例えば、
function get_count_properties($condition) {
    $oRecords = Sample1::where('value', $condition['sample1'])->get();
    $rec = [];
    foreach ($oRecords as $oRecord) {
        $rec[$oRecord->id] = Sample2::where('value', $condition['sample2'])
            ->where('sample1_id', $oRecord->id)->count();
    }
    return $rec;
}もろに1+N問題が発生しています。
Eager loading の解説にありますが、集合演算をうまく使うことで、この状況を回避できます。
function get_count_properties($condition) {
    $ids = Sample1:where('value', $condition['sample1'])->pluck('id');
    $rec = Sample2::select(DB::raw('count(*) as cnt'), 'sample1_id')
        ->where('value', $condition['sample2'])
        ->whereIn('sample1_id', $ids)
        ->groupBy('sample1_id')
        ->pluck('cnt', 'sample1_id')->toArray();
    return $rec;
}この実装では2回の SQL 発行で同じ結果が得られます。
レコード数が多いと前者の実装は不利になっていきます。XServer に30万件以上蓄積したテーブルで実測したところ、30秒程度要しました。後者の実行は1秒以内に終了します。

コメントを残す