标题写在前面的话
本来打算补充在MySQL百万级数据量查询优化这篇文章里,后来想想虽然都是优化,但已经算是两回事了,所以另开一篇文章来写laravel的性能优化方法
一、laravel批量更新方法
原理:该方法封装主要是基于update … case … when …
注意:因为在我们项目中,是根据模块分库了,所以在封装次方法时使用了动态connection,若数据库未分库则不需要
以下批量更新分为两种情况,主要是数据结构不同
-
批量更新相同的字段
例:['id'=>1,'name'=>'葡萄']['id'=>2,'name'=>'橙子']
这种情况下$updateColumn直接使用以下方法中注释那行代码即可,无需在遍历获取。
(也可以通过传参直接将要更新的字段传入,大家自行发挥) -
批量更新不同的字段
例:['id'=>1,'name'=>'葡萄']['id'=>2,'name'=>'橙子','age'=>18]
public function updateBatch($multipleData = [], $connection = 'core')
{
try {
if (empty($multipleData)) {
throw new \Exception("数据不能为空");
}
$tableName = \DB::getTablePrefix() . $this->getTable(); // 表名
$firstRow = current($multipleData);
// $updateColumn = array_keys($firstRow);
$updateColumn = collect();
collect($multipleData)->each(function ($info) use (&$updateColumn) {
$keys = array_keys($info);
$updateColumn = $updateColumn->merge($keys)->unique();
});
$updateColumn = $updateColumn->toArray();
// 默认以id为条件更新,如果没有ID则以第一个字段为条件
$referenceColumn = isset($firstRow['id']) ? 'id' : current($updateColumn);
unset($updateColumn[0]);
// 拼接sql语句
$updateSql = "UPDATE `" . $tableName . "` SET ";
$sets = [];
$bindings = [];
foreach ($updateColumn as $uColumn) {
$setSql = "`" . $uColumn . "` = CASE ";
foreach ($multipleData as $k => $data) {
if (array_key_exists($uColumn, $data)) {
$setSql .= "WHEN `" . $referenceColumn . "` = ? THEN ? ";
$bindings[] = $data[$referenceColumn];
$bindings[] = $data[$uColumn];
}
}
$setSql .= "ELSE `" . $uColumn . "` END ";
$sets[] = $setSql;
}
$updateSql .= implode(', ', $sets);
$whereIn = collect($multipleData)->pluck($referenceColumn)->values()->all();
$bindings = array_merge($bindings, $whereIn);
$whereIn = rtrim(str_repeat('?,', count($whereIn)), ',');
$updateSql = rtrim($updateSql, ", ") . " WHERE `" . $referenceColumn . "` IN (" . $whereIn . ")";
// 传入预处理sql语句和对应绑定数据
return \DB::connection($connection)->update($updateSql, $bindings);
} catch (\Exception $e) {
Log::error($e);
return false;
}
}