如何优化慢SQL将查询耗时从2分钟缩短至3秒内?
查询耗时过长优化方案
你的查询跑2分钟的核心原因是现有单列索引完全不匹配当前查询的过滤+排序逻辑,1000万数据量级下触发了低效的全量排序或大量回表,按下面的方式调整,稳定能在100毫秒级返回结果,远低于3秒的要求。
第一步:创建适配查询逻辑的联合索引
直接执行下面的建索引语句:
CREATE INDEX idx_call_combo ON `call` ( calltype, callcode, call_connect, call_date DESC, call_id DESC );
这个索引的设计逻辑完全贴合你的查询执行路径:
- 索引前三个字段对应WHERE里的三个等值匹配条件,数据库可以直接定位到所有同时满足
calltype='Regular'、callcode=98、call_connect=1的数据区间,不需要扫描无关数据 - 索引后两个字段的排序规则和你ORDER BY子句的规则完全一致,索引本身是有序结构,数据库不需要把符合条件的数据全部拉出来做文件排序(也就是执行计划里的
Using filesort,这是你当前查询慢的核心诱因) - 因为你加了
LIMIT 1,数据库沿着索引找到符合时间条件的第一条数据后,只需要做1次回表查询拿到SELECT里剩下的几个字段就可以返回结果,回表成本可以忽略不计。
为什么你现在建的单列索引起不到效果
多个独立的单列索引无法同时满足过滤+排序的需求:
- 优化器最多只能选择其中一个单列索引做过滤,选call_date索引的话,需要扫描2018年之前的所有数据,逐行判断是否满足另外三个过滤条件,扫描量极大
- 选其他单列索引的话,过滤完的结果集需要重新做排序,1000万量级下排序操作会占用大量磁盘和CPU,耗时自然会到分钟级。
建完索引后的校验
执行EXPLAIN加你的原查询,确认执行计划符合以下特征就说明索引生效:
type列显示为ref或range,不能是ALL(全表扫描)key列显示为你刚创建的idx_call_combo索引Extra列不出现Using temporary、Using filesort字样
如果你用的是MySQL 5.6及以下版本,建索引时不支持写
DESC排序规则也没关系,直接按正序建这五个字段的联合索引即可,优化器会自动反向扫描索引完成排序,一样不会触发文件排序。
非必须的辅助优化
如果后续数据量继续增长到亿级,可以考虑把2018年之前的冷数据归档到历史表,进一步缩小热数据的扫描范围,但当前1000万数据量下,只要联合索引建对,完全不需要做额外调整就能满足性能要求。
内容的提问来源于stack exchange,提问作者DevBugs
相关产品推荐
相关产品推荐

