我必须更新非常大的数据集,到目前为止我有这个:
protected function updateWidgetsDb($APIWidgets, $date)
{
echo "Eager loading...";
$widgets = Widget::where('date', $date)->get();
echo "Done\n";
echo "Updating...";
foreach ($APIWidgets as $APIWidget) {
$widget = $widgets->where('widget_id', $APIWidget->dimensions[0])->first();
if ($widget == null)
continue;
$widget->update(['revenue' => $APIWidget->metrics[0]->values[0]]);
}
echo "Done\n";
}
$APIWidgets
是一个通过外部API获取的数组。我只获取特定日期的数据,因此我只加载该数据库中已存在的数据。
widget_id
字段在DB
修改
我有大约60k的数据,我收到的约2k数据用于更新。这些2k的每条记录都有一个ID,已经可以在现有的60k数据中找到。因此,更新后,数据总和仍应为60k,而不是62k。
目前,更新过程大约需要10分钟。
答案 0 :(得分:1)
我可以提出两种方法来加速批量更新任务。我尝试重现您的问题,因此我在widgets
表格中创建了一组包含widget_id,date
和widget_id
索引的60k * 7项目。
首先让我们更快地获得$widget
。当我用
$widgets->where('widget_id', $APIWidget->id)
时
Widget::where('date', $date)
->where('widget_id', $APIWidget->id)
脚本变得快了400倍。看起来使用索引widget_id, date
获取2000 mysql比通过60000大小的集合搜索Laravel集合更快。查询的结果是16秒,集合的结果是6400秒。
然后让我们更快地更新。使用临时表只有一个查询更新表有一个很好的方法。因此,我创建了一个新实体WidgetUpdate
,其中包含表格widget_updates
和字段id, widget_id, revenue_new
。
我修改了你的方法:首先我收集一系列更新,然后
我在widget_updates
表中进行批量插入,毕竟我
执行单个更新查询。我的机器做了2.2秒,
快5倍。对我来说,最终加速是2000x。
protected function updateWidgetsDb($APIWidgets, $date)
{
echo "Updating...";
$updates = [];
foreach ($APIWidgets as $APIWidget) {
$widget = Widget::where('date', $date)
->where('widget_id', $APIWidget->dimensions[0])
->first();
if ($widget == null)
continue;
$updates[] = ['revenue_new' => $APIWidget->metrics[0]->values[0]];
}
# inserting and updating
WidgetUpdate::insert($updates);
DB::statement('UPDATE widgets, widget_updates ' .
'SET widgets.revenue=widget_updates.revenue_new '.
'WHERE widgets.id = widget_updates.widget_id');
echo "Done\n";
}
不要忘记在完成时清理临时表。