Laravel 裡面的 chunk 分塊效率問題

zxr615發表於2019-12-03

laravel裡面的chunk分塊效率問題

在批處理較大資料資料時,laravel提供了chunk處理大塊資料的方法,但資料量大了之後效率會非常慢

本次資料庫測試資料供有二十萬零一千(201000)條資料

<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use App\Models\Test as TestModel;

class Test extends Command
{
    protected $signature = 'db:test';

    /**
     * 處理時間
     * @return float\
     */
    public function microtime_float():float\
    {
        list($usec, $sec) = explode(" ", microtime());
        return ((float)$usec + (float)$sec);
    }

    public function chunkTest()
    {
        // 每次處理
        $speed = 1000;
        // 進度條
        $bar = $this->output->createProgressBar(TestModel::query()->count());
        // 記錄開始時間
        $timeStart = $this->microtime_float();
        // chunk 分塊處理資料
        TestModel::query()->chunk($speed, function ($item) use ($bar, $speed) {
            // 業務處理邏輯...
            // ....
            // 進度條步進{$speed}步
            $bar->advance($speed);
        });
        $bar->finish();

        // 處理完成,記錄結束時間
        $timeEnd = $this->microtime_float();
        $time = $timeEnd - $timeStart;
        // 輸出資訊
        $this->info('chunk用時:'. $time);
    }
}

執行:

php artisan db:test
201000/201000 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓] 100% chunk用時:138.11135005951

發現出了20w資料用了兩分多鐘,效率似乎有點低,解決方法

public function idTest()
{
    // 進度條
    $bar = $this->output->createProgressBar(TestModel::query()->count());
    $timeStart = $this->microtime_float();
    // 記錄最大的id
    $maxId = 0;
    // 每次處理多少條資料
    $speed = 1000;

    while (true) {
        $models = TestModel::query()
            // 每次迴圈加上id條件
            ->where('id', '>', $maxId)
            ->limit($speed)
            ->orderBy('id')
            ->get();

        // 處理具體業務邏輯...

        // 如果沒有資料就代表處理完成,break;
        if ($models->isEmpty()) {
            break;
        }

        // 記錄下本次的最大id,下次迴圈時當作條件
        $maxId = $models->max(['id']);

        $bar->advance($speed);
    }

    $timeEnd = $this->microtime_float();
    $time = $timeEnd - $timeStart;
    $bar->finish();
    $this->info('id條件用時: '. $time);
}

執行:

php artisan db:test
 201000/201000 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓] 100%id條件用時: 7.790333032608

20W資料只用了7秒

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章