Laravel 里面的 chunk 分块效率问题
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秒
本作品采用《CC 协议》,转载必须注明作者和本文链接
本帖由系统于 3年前 自动加精
高认可度评论:
Laravel 早就给你准备好轮子了,chunkById
@gangpula 看这篇文章的第三点 https://segmentfault.com/a/119000000885970...
这可以哦
Laravel 早就给你准备好轮子了,chunkById
虽然laravel封装好了,但是我更感谢你分享了你实现的想法
有大佬解释下chunk 和 chunkById 的使用场景?
不应该呀,chunk 怎么会慢的呢
@gangpula 看这篇文章的第三点 https://segmentfault.com/a/119000000885970...
chunkById
@xxx chunk就是
limit 1000,10
chunkById就是where id > ? limit 10
。如果查询结果没办法保证有序的话就用chunk,如果可以保持有序就chunkById比较快。
两个都测试了一下 ,发现并没有你说的那么明显的效果 ,,数据也是二十多万级别的 比你说的数据还要多,,只要id是主键效果没有区别