面试题:解释一下什么是全字段排序和rowid排序

「全字段排序」和「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;

全字段排序的执行流程:

  1. 读取满足status = 1的每一行数据,把id、order_no、create_time(查询需要的所有字段)全部取出;
  2. 将这些字段的完整数据写入sort_buffer
  3. sort_buffer中按create_time DESC排序;
  4. 直接返回排序后的结果(已包含所有需要的字段,无需再查数据)。
3. 核心特点
  • ✅ 优点:排序后无需回表,少一次 IO 操作;
  • ❌ 缺点:sort_buffer内存占用大(要存所有字段),如果查询字段多(比如 SELECT *),sort_buffer容易被占满,数据会溢出到磁盘,导致排序速度骤降;
  • 适用场景:查询字段极少(比如只查 1-2 个小字段)、排序数据量小的场景。

二、rowid 排序(Rowid Sort,改进型文件排序)

1. 定义

排序时,只把「排序键(ORDER BY 指定的列) + 行指针(主键 id / 物理行地址)」加载到sort_buffer,排序后再通过「行指针」回表读取需要的字段,需要回表但内存占用小

2. 执行原理(步骤拆解)

还是以上面的查询为例,rowid 排序的执行流程:

  1. 读取满足status = 1的每一行数据,只取出create_time(排序键)和id(主键,行指针);
  2. create_time + id写入sort_buffer(仅这两个值,内存占用极小);
  3. sort_buffer中按create_time DESC排序;
  4. 按排序后的id,逐行去聚簇索引回表,读取order_no字段;
  5. 拼接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溢出到磁盘,反而更慢。

总结

  1. 全字段排序和 rowid 排序是filesort的两种算法,核心区别是sort_buffer存储的内容和是否回表;
  2. rowid 排序是 MySQL 5.6 + 默认方案,内存占用小,适合字段多 / 数据量大的场景;
  3. 无论哪种 filesort,性能都远低于「覆盖索引 + 索引排序」,优化 ORDER BY 的核心还是建适配的索引。
相关推荐
Mem0rin5 分钟前
二分查找:左右边界
数据结构·算法
DB哥讲数据库11 分钟前
【ClickHouse安装教程】从零开始部署高性能列式数据库(附ClickHouse安装包)
数据库·clickhouse
lazily-c27 分钟前
数据结构模板
数据结构
TDengine (老段)35 分钟前
TDengine 第三方工具 — Telegraf、Kafka Connect、Flink、Spark
大数据·数据库·物联网·flink·kafka·时序数据库·tdengine
祖力558 小时前
数据结构的基本概念与单向链表(链表数据类型构造、创建、头插、尾插、头删、尾删)
数据结构·链表
小白勇闯网安圈9 小时前
Django 响应对象、文件上传与类视图
数据库·django·sqlite
努力的小雨10 小时前
同一份 SQL 跑多套环境:Ksql 变量怎么用才安全
数据库
科技绘图11 小时前
快鲸GEO vs 传统AI搜索优化:全链路自动化与高效内容生产在转化闭环上的对比
数据库·人工智能·自动化
ltl11 小时前
数据库作为 LLM 记忆体:语义缓存、RAG 与一致性
数据库
ltl11 小时前
WAL 与崩溃恢复:ARIES 协议怎么跑通
数据库