很多慢查询不是慢在 where,而是慢在 order by。执行计划里出现 Using filesort 时,不一定表示真的写了磁盘文件,它真正暴露的是 MySQL 没能直接复用索引顺序。
ORDER BY 的核心矛盾是:能沿索引顺序返回,就不必额外重排;一旦顺序不可复用,就要把候选行组织成排序输入,付出 sort buffer、临时文件和中间结果膨胀的成本。
先把机制边界说清楚
ORDER BY 的本质是结果集有序化。MySQL 要么利用索引叶子节点天然有序的特性边扫边返回,要么把候选行的排序键收集起来,在 sort buffer 里排序,数据太大时再借助临时文件做归并。前者是访问路径设计,后者是执行阶段补救。
整体路径
上面这张图先看粗线条:宏观上,排序链路先由优化器判断 where 条件和 order by 是否能共用同一棵索引。如果可以,执行器按索引顺序扫描,通常不需要额外排序;如果不可以,就先取出候选行、构造排序键、在内存或磁盘上排序,再按排序结果返回或回表取完整列。
底层流程
底层拆解先看数据结构。「ORDER BY」至少涉及下面几类结构:
- 索引叶子顺序:B+ 树叶子节点天然按索引键排列,是最理想的排序来源。
- sort buffer:每个排序线程使用的内存区域,用来保存排序键和必要字段。
- rowid 或主键引用:只排序键和行引用时,排序后还需要二次取行。
- 临时归并文件:排序数据超过内存能力时,用多路归并完成结果有序化。
再看完整执行流程:
- 优化器检查 order by 列、方向和访问索引是否兼容。
- 如果索引顺序可用,按索引范围顺序扫描并尽早应用 limit。
- 如果不可用,先读取候选行并构造排序记录。
- 在 sort buffer 中完成内存排序,必要时写临时文件归并。
- 按排序结果取回需要的列,并返回给客户端。
取舍与边界
版本差异上,MySQL 8.0 对降序索引支持更完整,order by a desc, b asc 这类混合方向更容易被索引顺序覆盖;8.0 还可以用 EXPLAIN ANALYZE 对比估算和实际耗时。5.7 时代更多依赖传统 explain、慢查询和状态计数推断排序成本。
ORDER BY 的短板在于它经常被产品需求放大。低选择性过滤后再排序,会让候选集很大;深分页会迫使 MySQL 排出大量用不到的行;sort buffer 是按线程使用的,盲目调大可能把并发内存打爆。
典型问题:用机制化例子排查
排序问题可以用一个列表查询理解:如果 where 条件和 order by 不能复用同一条索引顺序,MySQL 就要先拿候选行,再额外组织排序输入。
可以落到这些动作:
- 把 where 等值条件、排序列和稳定游标列放进同一条联合索引。
- 避免深 offset 分页,改用
(created_at, id)游标继续向后扫。 - 不要把 sort_buffer_size 当万能开关,先减少候选行和排序字段宽度。
- 排序字段方向混合时,确认当前 MySQL 版本是否能用降序索引覆盖。
收束:排序优先设计访问路径
ORDER BY 是一次顺序选择:要么设计一条本来就有序的访问路径,要么在执行时付出排序代价。核心列表接口应尽量走前者。
关于十三Tech
我是十三,All in AI Agent 方向的架构师,专注 AI 工程实践。
我相信 AI 是程序员的最佳搭档,也希望帮助每一位开发者更好地驾驭 AI。
如果你想继续跟完这套「图解 MySQL」,欢迎关注公众号 「十三Tech」。后续会继续按机制、图解和实战排查这条线更新。

