十万条记录聚合查询耗时20-21秒,如何优化该SQL语句?
针对你遇到的10万条记录聚合查询耗时20+秒的问题,我给你几个具体的优化方向,都是实际场景中亲测有效的:
SQL查询优化方案
1. 替换前缀索引为覆盖联合索引
你当前创建的source(30)前缀索引只能帮优化器快速定位source非空的行,但查询还需要product_price和quantity来计算总和,这时候数据库不得不回表去主键索引里取这两个字段的值——这是导致查询缓慢的核心原因。
建议直接创建包含查询所需所有字段的覆盖索引:
ALTER TABLE `dbname`.`sheet` ADD INDEX `idx_source_price_qty` (`source`, `product_price`, `quantity`);
创建完成后,执行EXPLAIN查看执行计划,如果Extra列显示Using index,说明数据库直接从索引里获取所有需要的数据,完全不需要回表,这能把查询时间直接降到毫秒级。
2. 优化WHERE条件的过滤逻辑
如果source字段的空字符串('')占比很高,可以先确认是否能用source IS NOT NULL代替source !=''?不过要注意两者的区别:空字符串是'',NULL是无值,得根据你实际的数据情况选择。如果必须保留source !='',覆盖索引也能帮优化器快速过滤掉不符合条件的行。
3. 确认存储引擎为InnoDB
如果你的表目前用的是MyISAM,建议直接切换到InnoDB:
ALTER TABLE `dbname`.`sheet` ENGINE=InnoDB;
InnoDB的聚簇索引结构在处理聚合查询和覆盖索引时,效率远高于MyISAM,尤其是数据量较大的场景,切换后性能会有明显提升。
4. 用执行计划验证优化效果
每次调整后,一定要用EXPLAIN确认优化器的选择是否符合预期:
EXPLAIN SELECT source, sum(product_price*quantity) AS price FROM `sheet` WHERE source !='' GROUP BY source ORDER BY `price` DESC;
重点关注这几个字段:
type列:最好是range或ref(如果source有大量唯一值,可能会显示ref)key列:是否用上了我们创建的idx_source_price_qtyExtra列:是否有Using index(覆盖索引生效的标志);如果ORDER BY的price是聚合后的结果,Using filesort可能无法避免,但只要覆盖索引生效,排序的开销会非常小。
5. 可选:预计算聚合结果(适合非实时查询)
如果你的数据不是需要实时更新的报表类查询,可以考虑每天定时预计算聚合结果,存到一个汇总表中:
-- 每天定时执行的预计算语句 INSERT INTO `sheet_summary` (source, total_price) SELECT source, sum(product_price*quantity) AS total_price FROM `sheet` WHERE source !='' GROUP BY source ON DUPLICATE KEY UPDATE total_price = VALUES(total_price); -- 查询时直接从汇总表取数据 SELECT source, total_price AS price FROM `sheet_summary` ORDER BY price DESC;
这种方式能把查询时间降到几乎为0,非常适合数据更新频率低的场景。
内容的提问来源于stack exchange,提问作者Sumit
相关产品推荐
相关产品推荐

