Eloquentのgetメソッドとchunkメソッドのパフォーマンスを比較してみる

## はじめに
下記の記事で大量データを扱う際は`chunk`メソッドを使った方が良いといった内容を書きましたが、実際にどれくらい良くなるかを今回は検証してみました

https://qiita.com/t1k2a/items/25f145135a16bc5e3f44

## パフォーマンステストの準備
- データベースの準備
    - テスト用のデータベースを用意し、十分なレコード数を挿入します
    - 今回は4000件のデータを使用します
- 環境の準備
    - 同じ環境でテストを行います
    - 今回はDocker＋Laravel＋MySQLの環境で行います
    - 詳しくは下記の記事をご参照ください

https://qiita.com/ucan-lab/items/5fc1281cd8076c8ac9f4


測定項目
- メモリ使用量
    - 各メソッド使用時のメモリ消費量を測定します
- 処理時間
    - 各メソッドが処理を完了するまでの時間を測定します

## テストデータの使用
テストデータは下記を使用しました

https://dev.mysql.com/doc/index-other.html

> world database

というDBのcityテーブルを使います
後続のモデルを作成をした際に使用するのでテーブル名は`cities`にしておきます

## モデルの作成
```bash
docker compose exec app php artisan make:model City
 ```
モデル名は単数形ですが、参照先のテーブル名は複数形であることを前提としています

https://readouble.com/laravel/9.x/ja/eloquent.html#:~:text=%7B%0A%20%20%20%20//%0A%7D-,%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E5%90%8D,-%E4%B8%8A%E8%A8%98%E3%81%AE%E4%BE%8B

## バッチでスクリプトを作成
今回はバッチファイルで検証します

- Laravelのartisanコマンドでバッチを作成
```bash
php artisan make:command TestPerformance
```
これにより、`app/Console/Commands/TestPerformance.php`というファイルが作成されます
このファイルを編集します

```TestPerformance.php
<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use App\Models\City;

class TestPerformance extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'app:test-performance';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Command description';

    /**
     * Execute the console command.
     */
    public function handle()
    {
        $this->testGetMethod();
        $this->testChunkMethod();
    }

    private function testGetMethod()
    {
        // メモリ使用量の初期値を取得
        $initialMemory = memory_get_usage();

        // 処理開始時間を取得
        $startTime = microtime(true);

        // getメソッドでcityを取得
        $cities = City::get();
        
        foreach ($cities as $city) {
            // ダミー処理
            $uppercaseName = strtoupper($city->name);
            $nameLength = strlen($uppercaseName);
            // ここで、変数 $uppercaseName と $nameLength を使用してダミーの処理を行う
            // 実際には何もしていないが、処理が行われたと仮定する
        }

        $endTime = microtime(true);

        // メモリ使用量の差分を計算
        $memoryUsage = memory_get_usage() - $initialMemory;

        // 処理時間を計算
        $executionTime = $endTime - $startTime;

        $this->info("getメソッドのメモリ使用量：" . $memoryUsage . "bytes");
        $this->info("getメソッドの処理時間: " . $executionTime . " seconds");
    }

    private function testChunkMethod()
    {
        // メモリ使用量の初期値を取得
        $initialMemory = memory_get_usage();

        // 処理開始時間を取得
        $startTime = microtime(true);

        // chunkメソッドでcityを分割して取得
        City::chunk(1000, function($cities) {
            foreach ($cities as $city) {
                // ダミー処理
                $uppercaseName = strtoupper($city->name);
                $nameLength = strlen($uppercaseName);
                // ここで、変数 $uppercaseName と $nameLength を使用してダミーの処理を行う
                // 実際には何もしていないが、処理が行われたと仮定する
            }
        });

        $endTime = microtime(true);

        // メモリ使用量の差分を計算
        $memoryUsage = memory_get_usage() - $initialMemory;

        // 処理時間を計算
        $executionTime = $endTime - $startTime;

        $this->info("chunkメソッドのメモリ使用量: " . $memoryUsage . " bytes");
        $this->info("chunkメソッドの処理時間: " . $executionTime . " seconds");
    }
}
```

## 計測結果
まず、citiesテーブルに格納されているデータ数は下記の通りになります

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282722/8b780ffa-75b1-317d-d64a-5a415ae5049f.png)

バッチ実行時の計測結果は下記の通りになります

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282722/a5ee5edb-4b76-d52a-1d03-790475598180.png)

getに対してchunkメソッドの方がメモリを使わずはるかに速い処理時間で完了していますね
これには自分でも驚きましたｗ

## おわりに
予想以上の結果に驚いております
大量データを扱って処理を記述する際はぜひ`chunk`メソッドを使ってみてください
そして「なぜそんなメソッドを使うのか？」と聞かれたら本記事の結果を共有してみてください！
さらに詳しい情報は公式ドキュメントも参照すると良いでしょう！

## 参考リンク

https://qiita.com/t1k2a/items/25f145135a16bc5e3f44

https://qiita.com/ucan-lab/items/5fc1281cd8076c8ac9f4

https://dev.mysql.com/doc/index-other.html

https://readouble.com/laravel/9.x/ja/eloquent.html#:~:text=%7B%0A%20%20%20%20//%0A%7D-,%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E5%90%8D,-%E4%B8%8A%E8%A8%98%E3%81%AE%E4%BE%8B