【问题标题】:Laravel Query Optimization (SQL)Laravel 查询优化 (SQL)
【发布时间】:2020-01-13 21:13:14
【问题描述】:

我的user_level数据库结构是

| user_id | level |
|       3 |     F |
|       4 |    13 |
|      21 |     2 |
|      24 |     2 |
|      33 |     3 |
|      34 |   12+ |

我还有一张桌子users

    |      id | school_id |
    |       3 |         3 |
    |       4 |         4 |
    |      21 |         2 |
    |      24 |         2 |
    |      33 |         3 |
    |      34 |         1 |

我必须实现的是,我必须根据某个预定义条件更新每个用户的level。但是,我的 users 表非常庞大,有数千条记录。

在一个实例中,我只更新特定学校的user_level 记录。比如说school_id = 3,我获取所有用户及其关联的等级,然后将这些用户的等级值增加1(F变为1,删除12+,所有其他数字都增加1)。

当我使用循环遍历用户时,匹配他们的user_id 然后更新记录,这将是数千个查询。这会降低整个应用程序的速度并导致其崩溃。

一个理想的事情是 laravel 交易,但我怀疑它是否优化了时间。我在一个包含大约 6000 条记录的简单查询中对其进行了测试,它运行良好。但是由于某种原因,它对我的​​记录没有那么好。

只是看一些关于任何其他查询优化技术的建议。

更新

我实现了一个解决方案,我将根据级别对所有记录进行分组(使用 laravel 集合),然后我只需要发出 13 个更新查询,而现在有成百上千个。

$students = Users::where('school_id', 21)->get();
$groupedStudents = $students->groupBy('level');
foreach ($groupedStudents  as $key => $value) :
        $studentIDs = $value->pluck('id');
        // condition to check and get the new value to update
        // i have used switch cases to identify what the next level should be ($NexLevel)
       UserLevel::whereIn('userId', $studentIDs)->update(["level" => $nextLevel]);
endforeach;

我仍在寻找其他可能的选择。

【问题讨论】:

  • 在一条 SQL 语句中进行更新,而不是无数次不同的更新。这通常更快。
  • @GordonLinoff 更多见解。不过,我将不得不遍历所有记录以检查条件。

标签: php sql laravel


【解决方案1】:

首先在你的模型中定义一个关系,比如:

在 UserLevel 模型中:

public function user() {
      return $this->belongsTo(\App\UserLevel::class);
}

而且您可以更新level 没有 12+ 级别的查询,仅通过一个查询,并删除所有 12+ 级别的查询

UserLevel::where('level', '<=', 12)->whereHas('user', function($user) {
    $user->where('school_id', 3);
})->update(['level' => DB::raw("IF(level = 'F', 1, level+1)")]);

UserLevel::whereHas('user', function($user) {
    $user->where('school_id', 3);
})->where('level', '>', 12)->delete();

如果您的数据太大。您也可以使用chunk 来拆分它们以减少内存消耗。

像这样:

UserLevel::where('level', '<=', 12)->whereHas('user', function($user) {
    $user->where('school_id', 3);
})->chunk(5000, function($user_levels) {
    $user_levels->update(['level' => DB::raw("IF(level = 'F', 1, level+1)")]);
});


UserLevel::whereHas('user', function($user) {
    $user->where('school_id', 3);
})->where('level', '>', 12)->delete();

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-10
    • 2014-02-04
    • 2014-11-16
    • 2011-06-22
    相关资源
    最近更新 更多