🐈

[Laravel]Collection::whereBetweenが遅い

2025/01/14に公開

はじめに

LaravelのCollection::whereBetween()からのCollection::count()が遅かったので、配列で処理した時との速度比較をしてみました。

動作環境

PHP 8.1.29
Laravel Framework 10.32.1

検証コード

private function countRange($nums, $from, $to) {
    $count = 0;
    foreach ($nums as $num) {
        if ($num >= $from && $num <= $to) {
            $count++;
        }
    }
    return $count;
}

public function run() {
    $COUNT = 1000;
    $BETWEEN_FROM = 0.3 * $COUNT;
    $BETWEEN_TO = 0.5 * $COUNT;

    // Collection作成
    $items = collect()->range(0, $COUNT)
        ->map(function ($index) use ($COUNT) {
            return [
                'id' => $index,
                'number' => random_int(0, $COUNT),
            ];
        });

    $collectionTotal = 0;
    $arrayTotal = 0;

    // 計測
    for ($i = 0; $i < 10; $i++) {
        // Collectionのまま処理
        $start = microtime(true);
        $items->whereBetween('number', [$BETWEEN_FROM, $BETWEEN_TO])->count();
        $collectionTotal += microtime(true) - $start;

        // 配列に変換してから処理
        $start = microtime(true);
        $numbers = $items->map(fn($item) => $item['number'])->toArray();
        $this->countRange($numbers, $BETWEEN_FROM, $BETWEEN_TO);
        $arrayTotal += microtime(true) - $start;
    }

    // 10回計測の平均値を出力する。
    var_dump("Collection:" . $collectionTotal / 10);
    var_dump("Array:" . $arrayTotal / 10);
}

検証結果

要素数 Collection Array
1,000件 0.00550秒 0.00059秒
10,000件 0.05393秒 0.00574秒
100,000件 0.52312秒 0.06067秒
1,000,000件 5.35373秒 0.66113秒
10,000,000件 61.88503秒 7.02155秒

大体9倍近くの差が出ました。
今回のケースはBetweenで絞った結果の件数を取得する処理でしたが、
他にもCollectionで処理する必要がない場合は、配列に変換してから処理した方が速度は有利ですね。

株式会社THIRD エンジニアブログ

Discussion