Laravelでfakerを利用し、Eloquentのcursor()・all()・chunk()の速度を計測するために、テストの点数のデータを登録してみた(Command)(第2回)


◆目的

chunk()・all()・cursor()の速度計測

前回の記事の続き
[前回の記事]https://qiita.com/hekizi/items/ef66918558d2a8c34ad7

◆Commandクラス準備

最近LaravelのCommandをちょっとやったので、それを使ってみようと思う。

コマンドクラスの作成
php artisan make:command MeasurementSpeedDataAcquisition
作成されたクラス
class MeasurementSpeedDataAcquisition extends Command
{
    //コマンド名
    protected $signature = 'measurement-speed-data-acquisition';

    //コマンドの詳細
    protected $description = 'DBからデータを取得する速度を測定する';

    public function __construct()
    {
        parent::__construct();
    }

    public function handle()
    {
        //コメント出力
        $this->comment('試しにコメント出力します。');
    }
}
コマンド
php artisan list
Available commands:
  measurement-speed-data-acquisition  DBからデータを取得する速度を測定する

コマンドが加わっています。試しに実行してみます。

コマンド
php artisan calculate-point-average
試しにコメント出力します。

ちゃんと出力されました。

◆取得する処理を実装していく

今回は、テストのため一つのクラスにすべて記述する。

MeasurementSpeedDataAcquisition
private $students = array();
private $getMethod  = '';
private $chunkSize  = '';

//allメソッドを利用
private function all()
{
    $this->students = Student::all();
}

//chunkメソッド利用
private function chunk()
{
    Student::chunk($this->chunkSize, function ($students){
        foreach ($students as $student){
            $this->students[] = $student;
        }
    });
}

//cursorメソッドを利用
private function cursor()
{
    foreach (Student::cursor() as $student) {
        $this->students[] = $student;
    }
}

取得メソッドをコマンドで使い分けたいので、少し工夫する

protected $signature = 'measurement-speed-data-acquisition {methodName} {chunkSize?}';

\$signatureの部分を変更し、 {methodName} {chunkSize?}を付け加える。
・{methodName}は省略するとエラーになる(文字列で受け取る)
・{chunkSize?}は省略可能

◆速度測定メソッドを作成する

MeasurementSpeedDataAcquisition
 public function handle()
{
    $this->getMethod = $this->argument('getMethod');
    $this->chunkSize = (int)$this->argument('chunkSize');

    $this->measureProcess();
}

private function measureProcess()
{
    echo '測定開始'. PHP_EOL;

    //現在時間をマイクロタイムで取得
    $startTime = microtime(true);

    //このクラスのメソッドを呼ぶ。
    call_user_func([__CLASS__, $this->getMethod]);

    //処理終了後の現在時間 - 処理前の時間
    $measureTime = microtime(true) - $startTime;

    printf("処理速度:%f". PHP_EOL, $measureTime);

    echo '測定終了'. PHP_EOL;
}

前回10000件のデータを入れているので、コマンド打って速度測定する。

・all 0.45
・cursor 0.48
・chunk(10) 11.3
・chunk(100) 1.69
・chunk(1000) 0.62

速度の差はそんなに見られなかった。今度はメモリ使用量を測定する。

MeasurementSpeedDataAcquisition
private function measureProcess()
{
    echo '測定開始'. PHP_EOL;
    echo 'メモリ使用量(start)' .memory_get_usage() / (1024 * 1024). 'MB'. PHP_EOL;

    //現在時間をマイクロタイムで取得
    $startTime = microtime(true);

    call_user_func([__CLASS__, $this->getMethod]);

    //処理終了後の現在時間 - 処理前の時間
    $measureTime = microtime(true) - $startTime;

    printf("処理速度:%f". PHP_EOL, $measureTime);
    echo 'メモリ使用量(end)' .memory_get_usage() / (1024 * 1024). 'MB'. PHP_EOL;
    echo 'メモリ最大使用量' .memory_get_peak_usage() / (1024 * 1024). 'MB'. PHP_EOL;

    echo '速度測定終了'. PHP_EOL;
}

・all
メモリ使用量(start)11.077095031738MB
処理速度:0.454851
メモリ使用量(end)26.890312194824MB
メモリ最大使用量27.851287841797MB

・cursor
メモリ使用量(start)11.077095031738MB
処理速度:0.487874
メモリ使用量(end)26.700172424316MB
メモリ最大使用量29.298736572266MB

・chunk10
メモリ使用量(start)11.077125549316MB
処理速度:12.246967
メモリ使用量(end)27.070137023926MB
メモリ最大使用量27.118766784668MB

・chunk100
メモリ使用量(start)11.077125549316MB
処理速度:1.347335
メモリ使用量(end)26.795478820801MB
メモリ最大使用量26.844108581543MB

・chuck1000
メモリ使用量(start)11.077125549316MB
処理速度:0.650694
メモリ使用量(end)26.768013000488MB
メモリ最大使用量26.88306427002MB

◆まとめ

あんま変わらんかった。検証方法間違えたかな?
公式では、大容量のデータを扱うにはcursorやchunkを使うほうがいいと書いてあるので使っていこうと思う

[参考記事]
https://blog.zuckey17.org/entry/2018/01/26/195029
http://kameryo.hatenablog.com/entry/2015/06/24/110559