面试题:解释一下什么是全字段排序和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 的核心还是建适配的索引。
相关推荐
老师用之于民8 分钟前
【DAY20】数据结构基础:(算法)排序、折半查找的函数实现
数据结构·算法·排序算法
松涛和鸣10 分钟前
DAY69 Practical Guide to Linux Character Device Drivers
linux·服务器·arm开发·数据库·单片机·嵌入式硬件
咩咩不吃草19 分钟前
Linux环境下MySQL的安装与使用与Navicat
linux·运维·数据库·mysql·navicat
Aloudata19 分钟前
NoETL 指标平台如何保障亿级明细查询的秒级响应?——Aloudata CAN 性能压测深度解析
数据库·数据分析·自动化·指标平台
闲人不梦卿20 分钟前
数据结构之查找的方法
数据结构
maoku6620 分钟前
从关键词到语义:向量数据库如何让AI真正理解你的需求
数据库·人工智能
寻道码路20 分钟前
【MCP探索实践】Google GenAI Toolbox:Google开源的企业级AI数据库中间件、5分钟搞定LLM-SQL安全互联
数据库·人工智能·sql·开源·aigc
数据知道21 分钟前
PostgreSQL 核心原理:一文掌握 WAL 缓冲区与刷盘策略(性能与数据安全的权衡)
数据库·postgresql
三个人工作室24 分钟前
mysql允许所有ip地址访问,mysql允许该用户访问自己的数据库【伸手党福利】
数据库·tcp/ip·mysql
小小逐月者25 分钟前
SQLModel 开发笔记:Python SQL 数据库操作的「简化神器」
数据库·笔记·python