执行计划显示 Using filesort,是否一定需要优化?给出判断条件
解读
-
面试官意图
国内互联网/金融/运营商等甲方公司,性能测试工程师往往要“左手压测、右手调优”。看到 Using filesort 就喊“必须加索引”是初级候选人的通病。面试官想确认你能否:- 区分“排序本身”与“排序带来的性能风险”
- 给出可量化的判断标准,而不是拍脑袋
- 把“要不要优化”与“业务 SLA、并发量、数据规模”挂钩
-
高频场景
- 订单列表、账单明细、日志查询等带分页+多字段排序的接口
- 数据量在百万级以下、并发 <50 QPS 的 ToB 系统
- 数据量过十亿、并发过千的 ToC 大促秒杀
不同场景对“Using filesort”容忍度完全不同,必须分情况讨论。
知识点
-
Using filesort 本质
MySQL 为完成 ORDER BY,需要在 Server 层额外开辟 sort_buffer 做快速排序或优先队列排序;是否走“文件”取决于 sort_buffer_size 与待排序数据量,不一定真落盘。 -
触发条件
- 索引无法完全覆盖 ORDER BY 字段顺序或方向(ASC/DESC 混用、表达式、函数)
- 关联查询中排序字段来自驱动表之外的表
- 使用了 DISTINCT/GROUP BY + ORDER BY 组合且索引不匹配
-
性能测试视角的量化指标
- 单 SQL 平均耗时 & P99 耗时
- 并发压测下该 SQL 的 QPS 曲线是否出现断崖
- 压测过程中 MySQL 实例的 CPU、IO 利用率是否因“Sort_merge_passes”暴涨
- 慢查询日志中因 filesort 产生的“Query_time”是否持续高于业务 SLA(如 100 ms)
-
可接受阈值(国内一线大厂内控基线)
- 非核心报表类:单 SQL P99 < 200 ms 且并发 50 以下,可暂缓优化
- 核心链路:单 SQL P99 > 50 ms 或 CPU 利用率因排序增长 >10%,必须优化
- 大促容量验证:未来 3 倍流量下,若 sort_merge_passes >1000/秒,必须优化
答案
不一定需要优化。判断条件如下,满足任意一条即进入优化流程,否则可接受:
- 业务 SLA 要求:接口 P99 响应时间 > 规定阈值(如 100 ms)且瓶颈跟踪到该 SQL 的 filesort;
- 容量测试结果:在目标并发(如 500 QPS)下,该 SQL 导致 MySQL 实例 CPU 利用率增幅 ≥10%,或磁盘 IO 因排序临时文件写入出现明显尖峰;
- 慢查询日志:近 7 天该 SQL 因 filesort 平均 Query_time 持续高于 100 ms,且执行频次占总量 ≥1%;
- 趋势预测:通过 3 倍流量压测,sort_merge_passes 增长率 >1000/秒,或 sort_buffer 频繁溢出导致磁盘临时表;
- 资源成本:单条 SQL 每次排序数据量 >4 MB(sort_buffer_size 默认 256 k~2 M),造成内存-磁盘交换,影响同实例其他业务。
若以上条件均不满足,可维持现状,仅加入监控基线并定期复盘。
拓展思考
-
索引方向一致性
国内很多表结构为了“兼容”升降序,干脆全部 ASC,结果 ORDER BY c1 DESC, c2 ASC 就必然 filesort。压测前可通过
ALTER TABLE … ADD INDEX idx (c1 DESC, c2 ASC) 消除排序,但需评估写入放大与磁盘占用。 -
延迟关联 + 覆盖索引
对分页深度较大的列表接口,可先用覆盖索引取出主键,再回表取行,减少排序数据量。性能测试需对比“深分页 20 页”场景下,filesort 版本与延迟关联版本的 P99 差距。 -
业务妥协
部分 ToB 场景允许“默认排序”走索引,“手动点击排序”才触发 filesort,且给出二次加载提示。此时性能测试重点从“消灭 filesort”转为“保证首次加载 <200 ms,二次排序可接受 1 s”。 -
8.0 的 Skip Scan 与 Hash-based ORDER BY
8.0.20 之后 MySQL 可在内存足够时直接用 hash 表排序,filesort 不一定走磁盘。性能测试报告需注明版本,避免“老版本经验”误导决策。