Laravel 优化求和查询

Laravel Optimise sum query

我想获得存款、取款和净额的总和。目前,我有 ~10,335,633 行数据(~1.8GB),计算总和需要超过 7 秒。我应该如何改进我的查询以使其更快?

查询:

$depositQuery = Deposit::whereBetween('created_at', [$start, $end])->approved();
$withdrawQuery = Withdraw::whereBetween('created_at', [$start, $end])->approved();

if ($request->has('user_id')) {
    $depositQuery = $depositQuery->where('user_id', $request->user_id);
    $withdrawQuery = $withdrawQuery->where('user_id', $request->user_id);
}

$deposits = $depositQuery->sum('amount');
$withdraws = ($withdrawQuery->sum('amount')) * -1;
$net = $deposits + $withdraws;

结果:

Deposit     Withdraw     Net Amount
20,946.00   15,066.00    5,880.00

基本上,laravel eloquent 与 sum() 的优化没有任何关系,它只是将您的代码转换为 SQL 查询。进入你的问题

Remeber: You can't optimize the sum function itself *(unless you are some real jedi)

你的数据库中有1M条记录,MySQLsum需要遍历所有记录才能计算出总和。在那种情况下,我认为 7 秒是可以的。根据这个问题here,一条7M的记录sum() table 大约用了22秒。因此,根据您的架构、机器等...速度可能会有所不同。

那么如何才能继续改进响应时间呢?

在将记录交给 sum() 处理之前,您必须以某种方式减少记录数。

我想你可以做的一种方法是,你可以计算 10k 记录的总和 batches/chunks 并将其存储在单独的 table 中,并具有适当的日期和时间范围。这个的广义术语是 archiving。然后,当您必须计算给定日期范围内的总和时,请使用新 table 中的先前完整总和并使用它。您可以设置一个 chron 作业来更新这个 table 一天之内的一个或其他东西以确保数据始终正确。

另一种方法是partition MySQL tables。这似乎也是一种很有前途的方式。这也是一种归档。但我不是很有经验,无法对此发表任何评论。 Google 应该能帮到你。

created_at 这样的列上的索引以及您用于批准范围的列应该会缩短响应时间,但与利用归档技术相比不会有太大的改善。

此外,我有 MySQLmysql 查询缓存 来自上面指定的相同 link 的答案,more info.您可以尝试使用。但是从 mysql 8 开始,它已被弃用,而且,如果您有多个实例 运行 并且如果您已分区 tables,它将无法按预期工作。