MySQL查询1.5亿级tracking_info表执行耗时过长问题求助
慢查询核心原因
- 最致命的问题是索引字段上使用函数导致索引完全失效:你的查询条件中对索引字段
time_recorded套用了FROM_UNIXTIME()函数,MySQL无法直接利用索引树做快速匹配,只能逐行计算函数值再判断是否符合时间条件,本质是在做全表扫描。1.5亿行数据逐行遍历计算的开销极高,这也是你移除ORDER BY后查询依然很慢的核心原因——全表扫描的耗时占了99%以上,排序本身的开销几乎可以忽略。 - 现有联合索引不符合最左前缀匹配规则:你创建的
tracking_idx顺序为(tracking_customer_id, tracking_type, time_recorded, tid),但查询中没有对tracking_type字段做等值过滤,直接跳过该字段对time_recorded做范围查询和排序,哪怕你修复了函数导致的索引失效问题,这个索引也无法利用time_recorded的有序性,依然会触发额外的扫描和排序开销。 - 存储引擎选型不适配大表场景:1.5亿数据量级的表使用MyISAM引擎存在天然性能短板,MyISAM没有聚簇索引、缓冲池优化能力弱,索引查询、回表取数的效率远低于InnoDB,也不支持行级锁,并发场景下性能问题会更明显。
可落地的优化方案
- 第一步先改写查询条件,移除字段上的函数计算:不要在
time_recorded字段上做时间格式转换,而是提前计算好90天前对应的UNIX时间戳,直接和原生字段值做比较,改写后的时间条件为:
改完后优化器才能识别范围条件,匹配对应的索引。time_recorded > UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL 90 DAY)) - 调整联合索引结构适配查询逻辑:新建联合索引
idx_customer_time (tracking_customer_id, time_recorded),这个索引的顺序完全匹配你的查询逻辑:先按tracking_customer_id做等值匹配,命中对应客户的所有索引项后,time_recorded在索引树中本身就是有序的,执行ORDER BY time_recorded DESC LIMIT 10时只需要反向扫描索引的前10条符合时间条件的记录,再回表取出对应的tracking_content、tracking_type字段即可,完全不需要全表扫描,也不会触发filesort,查询耗时可以直接降到毫秒级。如果后续有大量按tracking_type过滤的查询需求,也可以根据实际查询的过滤字段,把所有做等值匹配的字段放在联合索引靠前位置,范围查询、排序字段放在等值字段之后,保证索引利用率。 - 替换存储引擎为InnoDB:在测试环境验证数据一致性后,把表的引擎从MyISAM切换为InnoDB,利用InnoDB的聚簇索引、缓冲池特性进一步提升查询性能,同时也能获得更好的并发支持和崩溃恢复能力。
- 可选长期优化:如果单表数据量持续增长,可以按
time_recorded做时间范围分区,或者定期把超过业务查询窗口期的冷数据归档到单独的历史表,减少热表的常驻数据量,进一步降低查询开销。
优化完成后可以通过EXPLAIN查看执行计划,确认查询命中了新建的联合索引,Extra字段没有出现Using filesort、全表扫描相关的标记,就说明优化生效。
内容的提问来源于stack exchange,提问作者Vaeianor
相关产品推荐
相关产品推荐

