MySQL带日期过滤条件的分组查询执行过慢,如何优化
SQL查询性能优化方案
性能差异原因分析
- 无WHERE条件时,查询仅需对
subscription_subscription表的store_id字段分组统计,数据库可直接利用store_id上的索引完成聚合,无需回表扫描完整数据,因此执行速度极快。 - 新增日期过滤条件后,无适配索引的情况下,数据库需要全表扫描100万行数据逐行判断
end_date是否符合要求,再对符合条件的行做分组统计,额外的扫描和过滤操作导致耗时大幅上升。
优化方案
1. 新建联合覆盖索引(优先级最高)
给subscription_subscription表新建联合索引idx_sub_end_store,索引字段顺序为(end_date, store_id),建索引语句:
CREATE INDEX idx_sub_end_store ON subscription_subscription(end_date, store_id);
原理说明:该索引属于覆盖索引,包含了本次查询需要的所有字段:
- 前缀
end_date可快速定位所有满足CURRENT_DATE() <= end_date的行,跳过不符合要求的大量数据- 第二列
store_id可直接用于分组统计,不需要回表查询主键数据,整个查询完全在索引中完成,性能可提升数倍到数十倍。
2. 避免字段隐式类型转换
确认end_date字段的类型为DATE类型,不要使用字符串、DATETIME/TIMESTAMP类型存储日期值,避免类型隐式转换导致索引失效。如果确实需要使用DATETIME类型,可以将过滤条件调整为CURRENT_TIMESTAMP() <= end_date,保证字段和过滤值的类型一致。
3. 预聚合方案(适配非强实时场景)
如果业务对统计数据的实时性要求不高(允许T+1或者小时级延迟),可以新增一张订阅统计汇总表,每天/每小时定时执行统计任务,提前把每个门店的有效订阅数计算好存入汇总表,查询时直接读取汇总表即可,耗时可降低到毫秒级。
4. 优化器适配
如果新建索引后优化器仍未选择该索引,可手动强制指定索引(以MySQL为例):
SELECT store_id, COUNT(*) AS sub_store FROM subscription_subscription FORCE INDEX(idx_sub_end_store) WHERE CURRENT_DATE() <= end_date GROUP BY store_id ORDER BY sub_store DESC
内容的提问来源于stack exchange,提问作者Mojtaba Arezoomand
相关产品推荐
相关产品推荐

