应通过show status like 'sort%'查看sort_merge_passes是否为0来判断order by是否纯内存排序:若sort_merge_passes=0且sort_scan>0,大概率走内存排序;若≥1,则已触发磁盘归并排序。

怎么查ORDER BY是否用了sort_buffer?
直接看SHOW STATUS里和排序相关的计数器,而不是只盯着EXPLAIN。因为EXPLAIN只能告诉你“有没有filesort”,但看不出内存用没用满、有没有落盘。
执行完带ORDER BY的查询后,立即运行:
SHOW STATUS LIKE 'Sort%';
重点关注这三个值:
-
Sort_merge_passes:归并趟数。每大于0,基本说明数据超出了sort_buffer_size,开始写磁盘临时文件了 -
Sort_scan:通过全表/全索引扫描后排序的次数 -
Sort_range:在范围扫描后排序的次数
如果Sort_merge_passes持续增长,尤其是单次查询就触发多次归并,说明当前sort_buffer_size太小,排序被迫分块落盘。
为什么调大sort_buffer_size不一定更快?
sort_buffer_size是每个连接独占分配的内存,不是全局共享池。设成2M和设成32M,对单条查询的排序速度影响可能不大,但并发一上来,内存就炸了。
常见误操作是把sort_buffer_size从默认的256K直接拉到4M甚至更大,结果发现QPS掉了一半——其实是OOM Killer开始杀进程了。
更稳妥的做法是:
- 先观察高峰期的
Sort_merge_passes和连接数,估算总内存开销:max_connections × sort_buffer_size - 确保这个值不超过物理内存的10%~15%
- 优先优化SQL和索引,让
Using filesort消失,比硬堆内存更有效
如何区分内存排序和磁盘排序?
MySQL不对外暴露“本次排序用了多少MB内存”这种指标,但可以通过组合线索判断:
- 如果
Sort_merge_passes = 0且Sort_scan > 0,大概率是纯内存排序(前提是数据量没超过sort_buffer_size) - 如果
Sort_merge_passes ≥ 1,一定发生了磁盘排序;数值越大,落盘越频繁 - 配合
innodb_buffer_pool_reads突增,基本能确认排序过程引发了大量随机IO
注意:read_rnd_buffer_size也参与排序流程(用于回表读取非索引字段),但它只在Using filesort + Using temporary共存时才真正起作用,别和sort_buffer_size混淆。
EXPLAIN里的Using filesort到底意味着什么?
Using filesort只是表示“MySQL要额外做排序”,不代表一定用磁盘。它可能是内存排序,也可能是磁盘排序,EXPLAIN不区分。
真正决定走哪条路的是数据量和sort_buffer_size的关系:
- 数据总量 ≤
sort_buffer_size→ 内存排序(快) - 数据总量 >
sort_buffer_size→ 分块+归并+落盘(慢,且Sort_merge_passes上升)
所以看到Using filesort,第一反应不应该是调大sort_buffer_size,而是检查:WHERE条件是否能走索引、ORDER BY字段有没有被覆盖、是否用了函数或混合ASC/DESC——这些才是根因。











