菜单 学习猿地 - LMONKEY

VIP

开通学习猿地VIP

尊享10项VIP特权 持续新增

知识通关挑战

打卡带练!告别无效练习

接私单赚外块

VIP优先接,累计金额超百万

学习猿地私房课免费学

大厂实战课仅对VIP开放

你的一对一导师

每月可免费咨询大牛30次

领取更多软件工程师实用特权

入驻
70
0

Laravel 里面的 chunk 分块效率问题

原创
05/13 14:22
阅读数 618

laravel里面的chunk分块效率问题

在批处理较大数据数据时,laravel提供了chunk处理大块数据的方法,但数据量大了之后效率会非常慢

本次数据库测试数据供有二十万零一千(201000)条数据

chunk方法

<?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数据用了两分多钟,效率似乎有点低,解决方法

记录最大id方法:

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秒

发表评论

0/200
70 点赞
0 评论
收藏
为你推荐 换一批