我有一个代码,它从外部API获取数据,然后将其提交给DB:
protected function saveWidgetsToDatabase($widgetsDaily, Boost $boost, $date)
{
echo "Saving widgets to DB... ";
$widgets = Widget::all();
foreach ($widgetsDaily as $widgetDaily) {
$existingWidget = $widgets
->where('widget_id', $widgetDaily->id)
->where('date', $date)
->first();
if ($existingWidget === null)
$boost->widgets()->save(new Widget([
...
]));
else
$existingWidget->update([
...
]);
}
}我的关系是,一个Boost有很多Widgets。现在,我面临的问题是瓶颈DB保存/更新,因为只有当小部件具有相同的日期和ID时,我才需要更新它,否则我需要创建一个新的。
我们谈论的是几千条记录,所以我相信where条款是相当密集的。
我想要一批储蓄,虽然我没能做到。
有没有机会让这件事更快些?
发布于 2017-10-25 00:48:52
当您调用Widget::all();时,它将获取数据库中的每个小部件记录,并为其创建一个Widget实例。因此,$widgets将是存储在数据库中的每个Widget对象的Collection。如果您有10000个小部件记录,那么Collection将有10000个Widget对象。这显然不是你想要的。
这也意味着,当您调用$widgets->where()...时,您将调用Collection对象上的where(),该对象使用Collection过滤对象集合,而不是使用Collection过滤数据库结果。
有几件事你可以做。
首先,您知道您只关心那些在$widgetsDaily列表中有一个id的小部件。因此,将Widget查询限制为只包括ids列表中有widget_id的记录。
其次,还将日期查找添加到数据库查询中。
第三,通过widget_id字段键入结果集合,这样您就可以通过widget_id直接访问项,而不必每次循环遍历整个集合来查找它。
protected function saveWidgetsToDatabase($widgetsDaily, Boost $boost, $date)
{
// Get the only widget_ids we care about (assumes $widgetsDaily is a collection)
$ids = $widgetsDaily->pluck('id')->all();
// Get the target widgets from the database. This collection will only
// contain widgets that we actually care about.
$widgets = Widget::whereIn('widget_id', $ids)
->where('date', $date)
->get()
->keyBy('widget_id'); // rekey the resulting collection
foreach ($widgetsDaily as $widgetDaily) {
// Because the collection was rekeyed on widget_id, you can use
// get(id) instead of having to use where('widget_id', id)->first()
$existingWidget = $widgets->get($widgetDaily->id);
if ($existingWidget === null)
$boost->widgets()->save(new Widget([
...
]));
else
$existingWidget->update([
...
]);
}
}https://stackoverflow.com/questions/46896075
复制相似问题