Sort Buffer 是MySQL中每个连接独享的内存区域,仅存储排序键和回表ID,并非整行数据;当排序字段总宽×预估行数超过sort_buffer_size时会触发磁盘临时文件,真正影响性能的是Sort_merge_passes飙升。

Sort Buffer 是什么,它真能全靠内存排完序?
MySQL 的排序不是“把所有数据读进内存再 sort”这么简单。sort_buffer_size 只是一块预分配的内存区域,用来暂存排序所需的字段(比如 ORDER BY a, b 中的 a 和 b 值),不是整行记录。如果要排序的字段总大小 × 预估行数 > sort_buffer_size,就会触发磁盘临时文件(filesort 的“file”就在这儿)。
常见错误现象:Using filesort 出现在 EXPLAIN 的 Extra 列里,并不等于性能差——它只是说明没用到索引覆盖排序,但未必真写了磁盘;真正伤性能的是 Sort_merge_passes 状态变量飙升,代表多次归并磁盘块。
-
sort_buffer_size是每个连接独享的,调太大反而容易 OOM,尤其高并发时 - 只影响单个
ORDER BY操作,不会跨语句复用 - 它不存原始行数据,也不存
SELECT *的所有列——只存排序键和用于回表的 ID(比如主键)
什么时候会退化成磁盘排序?关键看这三点
判断是否落地磁盘,核心是看三组数据的大小关系:排序字段总宽 × 估算扫描行数 vs sort_buffer_size vs max_length_for_sort_data(控制是否启用“优化排序模式”)。
使用场景举例:查 10 万行,ORDER BY created_at,该字段是 DATETIME(8 字节),若 sort_buffer_size = 256K,理论最多缓存约 256×1024 ÷ 8 ≈ 32768 行——超了就得写磁盘临时文件。
- 开启
optimizer_switch='index_merge=on'不影响排序路径,别指望它绕过 filesort -
max_length_for_sort_data默认 1024,设太小会导致 MySQL 放弃“优化模式”,改用“原始模式”(存更多字段进 sort buffer,更容易撑爆) - 执行
SHOW STATUS LIKE 'Sort%';后重点关注Sort_merge_passes:值持续增长,基本确认频繁磁盘归并
ORDER BY + LIMIT 能跳过排序吗?不能,但可以剪枝
很多人以为 ORDER BY x LIMIT 10 就只排前 10 名——错。MySQL 仍需对满足 WHERE 条件的所有行排序,再取头 10。除非有合适索引覆盖 WHERE + ORDER BY,否则 sort_buffer 该用多少还是多少。
性能影响明显:没有索引时,LIMIT 10 和 LIMIT 1000000 在排序阶段消耗几乎一样,只是最后返回数据量不同。
- 复合索引
(status, created_at)可让WHERE status='active' ORDER BY created_at LIMIT 10完全避免 filesort -
ORDER BY RAND()强制全表扫描+全量入 sort buffer,不管LIMIT多小,都大概率触发磁盘排序 - 如果业务允许近似结果,用
OFFSET分页替代大偏移LIMIT,或改用基于游标的分页(WHERE id > ? ORDER BY id LIMIT 10)
怎么调 sort_buffer_size 才不算瞎搞?
别一上来就设成 256M。它不是越大越好,而是要匹配你最重的那类排序查询的典型数据规模。先观察,再调整。
实操建议:
- 查
SHOW VARIABLES LIKE 'sort_buffer_size';,默认通常 256K,对多数中小查询够用 - 用
SELECT @@sort_buffer_size;看当前会话值,确认没被会话级 SET 覆盖 - 监控
Sort_merge_passes / Questions比值,长期 > 0.01 就值得查具体哪些 SQL 触发了磁盘归并 - 线上调优优先加索引,其次考虑增大
sort_buffer_size;盲目调大可能挤占其他内存结构(如join_buffer_size、read_buffer_size)
真正容易被忽略的是:sort buffer 的生命周期只在单条语句内,语句结束立刻释放。它不像 InnoDB Buffer Pool 那样长期驻留——所以“调大一点省得频繁分配”的想法,在这里不成立。










