ORDER BY 是否触发 Filesort 取决于索引能否覆盖排序需求:必须满足最左前缀匹配、字段顺序与方向严格一致,且 WHERE 条件不中断索引连续性;EXPLAIN 中 Extra 出现 Using filesort 即表示未走索引排序,即使 WHERE 已用索引。

ORDER BY 用不用 Filesort,关键看索引是否“覆盖排序需求”
MySQL 优化器不会因为写了 ORDER BY 就一定走索引排序;它只在索引的顺序能直接满足 ORDER BY 子句(包括方向、字段顺序、范围条件位置)时,才跳过 Filesort。否则,哪怕有索引,也会回表+Filesort。
- 必须满足:索引最左前缀字段完全匹配
ORDER BY字段,且顺序一致(如索引是(a,b,c),ORDER BY a,b可用;ORDER BY b,a不可用) - 方向要一致:如果索引是
(a ASC, b DESC),而查询写ORDER BY a ASC, b ASC,即使字段对得上,也会触发 Filesort - WHERE 条件会截断索引:比如索引
(a,b,c),查询WHERE a = 1 AND c = 3 ORDER BY b—— 因为c不在索引中间连续位置,b实际不可排序,仍用 Filesort - 混合 ASC/DESC 在旧版本(
EXPLAIN 中的 Extra 字段是唯一可信判断依据
别猜,直接看 EXPLAIN 输出里的 Extra 列:
- 出现
Using filesort→ 确实走了 Filesort,不管有没有索引 - 没出现该字样,且
type是range/ref等,说明排序由索引完成 -
Using index出现 ≠ 排序用了索引——它只表示“覆盖索引”,和排序无关;要两者同时满足才真正高效 - 注意
key列:它显示实际选中的索引名,对照你的ORDER BY字段顺序,立刻知道是否“对得上”
ORDER BY + LIMIT 组合容易误判性能
很多人以为加了 LIMIT 10 就一定快,但优化器可能仍选择全量 Filesort 再截断,尤其当 WHERE 过滤性差时:
- 例如
SELECT * FROM orders WHERE status != 'cancelled' ORDER BY create_time DESC LIMIT 10,若status区分度低(90% 都不是 cancelled),优化器大概率放弃索引排序,改走 Filesort + 全表扫描 - 解决思路不是加索引,而是重构查询:先用覆盖索引快速定位最新时间点,再反查(即“延迟关联”),或增加更有效的过滤条件
-
ORDER BY ... LIMIT N在没有合适排序索引时,N 越大,Filesort 成本越高——不是线性,是 O(N log N) 甚至更差(取决于内存是否够用)
Filesort 的两种模式:优先队列 vs 传统磁盘排序
MySQL 5.6+ 默认启用 sort_buffer_size 内存排序,但具体走哪条路径,取决于数据量和配置:
- 若排序结果能全部放进
sort_buffer_size,走“优先队列(priority queue)”模式,时间复杂度接近 O(N log M),M 是 LIMIT 行数,非常高效 - 否则退化为传统两阶段:先读所有行→排序→取 LIMIT → 内存不够时写临时文件,I/O 开销陡增
- 可通过
SHOW STATUS LIKE 'Sort_merge_passes'监控磁盘排序次数;值持续 > 0,说明sort_buffer_size太小或查询设计不合理 - 注意:增大
sort_buffer_size是会话级的,不要全局设过大(每个连接都分配),容易撑爆内存
最容易被忽略的一点:ORDER BY 是否用索引,和 WHERE 用不用索引是两套决策逻辑。一个查询可能 WHERE 走了索引,但 ORDER BY 依然触发 Filesort——这时候光看 key 列不顶用,必须盯死 Extra 里有没有 Using filesort。










