为何MySQL中SUM聚合查询耗时极长?添加LIMIT 100仍无改善
为什么MySQL中sum(amount)比简单查询慢这么多?
这事儿其实很好理解,咱们拆解下两个查询的本质差异,再结合你的执行计划,就能找到问题根源了:
核心原因:两个查询的执行逻辑天差地别
select amount from amounts limit 100;:这个查询非常“偷懒”——MySQL只需要定位到表的起始位置,读取前100条记录的amount字段就直接返回了,全程只处理了100条数据,耗时自然可以忽略不计。select sum(amount) from amounts limit 100;:这里的sum()是聚合函数,它的工作逻辑必须遍历全表所有2800多万条记录,把每条的amount值累加起来才能得到最终总和。而且你加的limit 100完全是多余的——sum()本身只会返回1行结果,limit对这个结果没有任何过滤作用,MySQL还是得老老实实扫完所有记录,这就是耗时9秒多的关键。
再看你的执行计划,type: ALL明确标记了这是全表扫描,rows: 28022610也直接印证了MySQL需要遍历所有记录来完成求和计算。
优化方案
针对你的场景,给你几个实用的优化方向:
- 移除多余的
limit 100:它对sum()的结果没有任何影响,只会造成误解,删掉即可。 - 频繁全表sum?用汇总表:如果需要经常计算全表的
amount总和,建议创建一个汇总表(比如amounts_summary),里面存储总金额和更新时间。然后用定时任务(比如每天凌晨)执行:
之后查询总和直接从INSERT INTO amounts_summary (total_amount, update_time) SELECT SUM(amount), NOW() FROM amounts ON DUPLICATE KEY UPDATE total_amount = VALUES(total_amount), update_time = NOW();amounts_summary取,速度能提升几个数量级。 - 针对特定子集sum?加联合索引:如果你的求和是针对某个过滤条件的子集(比如
where user_id = 123),一定要给过滤字段和amount建联合索引,比如:
这样MySQL可以通过索引直接定位到符合条件的记录,无需全表扫描,聚合速度会大幅提升。CREATE INDEX idx_filter_amount ON amounts(filter_column, amount); - 优化字段类型:如果
amount用的是浮点型(比如double),可以考虑换成decimal或者整数型(比如把金额转成分存储为bigint),浮点型的计算开销比整数略高,虽然不是主要瓶颈,但能优化一点是一点。
内容的提问来源于stack exchange,提问作者user2320239
相关产品推荐
相关产品推荐

