我想得到存款,取款和净计数。目前,我有~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查询。并进入你的问题
记住:你不能优化sum函数本身*(除非你是一些真正的jedi)
您的数据库中有1M条记录,并且MySQL sum必须通过所有记录来计算总和。在那种情况下,我认为7秒是可以的。根据here这个问题,sum()
在7M记录表上花了大约22秒。所以取决于你的架构,机器等......速度可能会有所不同。
那么如何才能继续改善响应时间?
不知何故,在将数据提供给sum()
进行处理之前,您必须减少记录数量。
我认为你可以做的一种方法是,你可以计算10k记录批次/块的总和,并将其存储在一个单独的表中,具有适当的日期和时间范围。这方面的广义术语是归档。然后,当您必须计算给定日期范围的总和时,请使用新表中的前一个完整总和并使用它。您可以设置一个计时作业,以便在一天内更新此表,或者确保数据始终正确。
另一种方式是partition MySQL tables。这也似乎是一种很有前途的方式。这也是一种归档。但我对它的评论不是很有经验。谷歌应该帮助你。
像created_at
这样的列的索引以及用于批准范围的列应该可以改善响应时间,但不会像利用归档技术那样多。
另外,我在上面指定的同一链接more info的答案中有MySQLmysql查询缓存。哪个你可以试试用。但是,从mysql 8开始,它已被弃用,而且,如果你有多个实例正在运行并且你有分区表,它将无法正常工作。