「全字段排序」和「rowid 排序」这两个关键概念,它们其实是 MySQL 执行filesort(文件排序)时的两种核心算法。
先明确核心前提
这两种排序都是「没有合适索引时,MySQL 被迫做文件排序」的内部实现方式,目的都是完成 ORDER BY 的排序需求,但数据读取方式、内存占用、性能差异极大 ------MySQL 5.6+ 已默认优先使用 rowid 排序(更高效)。
一、全字段排序(Full Sort)
1. 定义
排序时,把查询需要的所有字段 (SELECT 列 + ORDER BY 列 + WHERE 列)都加载到sort_buffer(排序缓冲区),排序后直接返回结果,无需回表。
2. 执行原理(步骤拆解)
以这个查询为例(无覆盖索引,触发 filesort):
sql
SELECT id, order_no FROM t_order WHERE status = 1 ORDER BY create_time DESC;
全字段排序的执行流程:
- 读取满足
status = 1的每一行数据,把id、order_no、create_time(查询需要的所有字段)全部取出; - 将这些字段的完整数据写入
sort_buffer; - 在
sort_buffer中按create_time DESC排序; - 直接返回排序后的结果(已包含所有需要的字段,无需再查数据)。
3. 核心特点
- ✅ 优点:排序后无需回表,少一次 IO 操作;
- ❌ 缺点:
sort_buffer内存占用大(要存所有字段),如果查询字段多(比如 SELECT *),sort_buffer容易被占满,数据会溢出到磁盘,导致排序速度骤降; - 适用场景:查询字段极少(比如只查 1-2 个小字段)、排序数据量小的场景。
二、rowid 排序(Rowid Sort,改进型文件排序)
1. 定义
排序时,只把「排序键(ORDER BY 指定的列) + 行指针(主键 id / 物理行地址)」加载到sort_buffer,排序后再通过「行指针」回表读取需要的字段,需要回表但内存占用小。
2. 执行原理(步骤拆解)
还是以上面的查询为例,rowid 排序的执行流程:
- 读取满足
status = 1的每一行数据,只取出create_time(排序键)和id(主键,行指针); - 将
create_time + id写入sort_buffer(仅这两个值,内存占用极小); - 在
sort_buffer中按create_time DESC排序; - 按排序后的
id,逐行去聚簇索引回表,读取order_no字段; - 拼接
id + order_no后返回结果。
3. 核心特点
- ✅ 优点:
sort_buffer内存占用极小(仅存排序键 + 主键),不容易溢出到磁盘,排序效率更高; - ❌ 缺点:排序后需要回表(随机 IO),但回表的开销远小于「sort_buffer 溢出到磁盘」的开销;
- 适用场景:查询字段多(比如 SELECT *)、排序数据量大的场景(MySQL 默认优先用这种)。
三、全字段排序 vs rowid 排序(核心区别)
| 对比维度 | 全字段排序 | rowid 排序 |
|---|---|---|
sort_buffer内容 |
所有查询字段(SELECT/ORDER BY/WHERE) | 仅排序键 + 主键(rowid) |
| 内存占用 | 大 | 小(仅前者的 1/10 甚至更少) |
| 是否回表 | 否 | 是 |
| 触发条件 | 查询字段总长度 ≤ max_length_for_sort_data(默认 1024 字节) |
查询字段总长度 > max_length_for_sort_data |
| MySQL 默认(5.6+) | 仅字段极少时触发 | 优先使用(默认开启rowid_orderby=on) |
| 性能 | 字段少快、字段多慢 | 字段多快、字段少略慢(回表开销可忽略) |
四、回表会不会让 ORDER BY 变慢
- 如果触发 filesort 且用全字段排序:无回表,但内存占用大,字段多 / 数据量大时排序本身变慢;
- 如果触发 filesort 且用rowid 排序:有回表,但排序本身更快,回表的随机 IO 是主要开销;
- 但无论哪种 filesort,性能都远不如「覆盖索引 + 索引排序」
五、如何控制这两种排序(可选)
MySQL 通过max_length_for_sort_data参数控制算法选择(默认 1024 字节):
-- 查看当前值(单位:字节)
SHOW VARIABLES LIKE 'max_length_for_sort_data';
-- 临时调整(会话级)
SET SESSION max_length_for_sort_data = 2048;
- 如果查询字段的总长度 ≤ 这个值:用全字段排序;
- 如果超过这个值:用 rowid 排序。
⚠️ 不建议随意调大这个值:如果查询字段多,调大后会强制用全字段排序,导致sort_buffer溢出到磁盘,反而更慢。
总结
- 全字段排序和 rowid 排序是
filesort的两种算法,核心区别是sort_buffer存储的内容和是否回表; - rowid 排序是 MySQL 5.6 + 默认方案,内存占用小,适合字段多 / 数据量大的场景;
- 无论哪种 filesort,性能都远低于「覆盖索引 + 索引排序」,优化 ORDER BY 的核心还是建适配的索引。