我在Laravel 5.7的顶部有一个使用PHP编写的项目。我正在使用Eloquent ORM与数据库进行交互。
从数据库中提取很多记录后,我需要能够更新很多记录。
这就是我要尝试的方式。
$records = Record::where('Key','Test')->get();
$values = collecT([
['Id' => 1, 'Col' => 100],
['Id' => 2, 'Col' => 200],
['Id' => 3, 'Col' => 500],
....
]);
foreach($records as $record) {
$newValue = $values->where('Id', $record->id)->first();
if(is_null($newValue)){
continue;
}
$record->ColName = $newValue['Col'];
$record->save();
}
以上代码未将更新后的值写入数据库。但是,如果执行以下操作,它将更新
foreach($values as $value) {
$record = Record::where('Key','Test')->where('id', $value['Id'])->first();
if(is_null($record)){
continue;
}
$record->ColName = $value['Col'];
$record->save();
}
尽管上面的代码有效,但我必须为$values
数组中的每条记录做出1 select + 1 update语句。如果$values
数组的大小为1000。这将最多生成2000个疯狂的查询!
如何在不进行范围更新的情况下正确更新数据库中的多个记录。
答案 0 :(得分:1)
如果您尝试更新的所有行都将获得相同的值,则这是一个简单的问题。这个问题变得更加棘手,因为所有行都需要使用不同的值进行更新。 This comment在laravel的github问题上提供了一种解决方案,该解决方案可以通过单个查询来实现,在这种情况下,与逐行更新相比,这种方式可以使他对1000行进行13倍性能提升。
public static function updateValues(array $values)
{
$table = MyModel::getModel()->getTable();
$cases = [];
$ids = [];
$params = [];
foreach ($values as $id => $value) {
$id = (int) $id;
$cases[] = "WHEN {$id} then ?";
$params[] = $value;
$ids[] = $id;
}
$ids = implode(',', $ids);
$cases = implode(' ', $cases);
$params[] = Carbon::now();
return \DB::update("UPDATE `{$table}` SET `value` = CASE `id` {$cases} END, `updated_at` = ? WHERE `id` in ({$ids})", $params);
}
您也可以尝试使用https://github.com/mavinoo/laravelBatch进行类似的操作。