当前位置: 首页 > news >正文

MySQL 中的“双路排序”与“单路排序”:原理、判别与实战调优

一句话导读
ORDER BY 不能走索引时,MySQL 会在 Server 层做一次 filesort。内部实现分 单路(全字段)双路(rowid) 两种;了解它们的触发条件、判别方法与调优思路,是 SQL 性能优化的必修课。


一、为什么会有 filesort?

  • 当查询无法利用 覆盖索引索引顺序 满足 ORDER BY 时,MySQL 需要把结果集读出来再排序。

  • 这个排序逻辑统称 filesort,但它未必落盘,绝大多数情况下在内存完成。


二、单路 vs 双路:一张图看懂差异

阶段单路排序 (Single-Pass)双路排序 (Two-Pass)
读取列所有查询列一次性读入 sort buffer只读 排序键 + rowid
排序对象完整记录<排序键, rowid> 二元组
回表不需要按 rowid 二次回表取整行
内存消耗高(存整行)低(只存键+id)
I/O 特征顺序读一次随机读两次
典型触发查询列总字节 ≤ max_length_for_sort_data超过阈值或含大 TEXT/BLOB

三、内部流程拆解

  1. 单路排序

    1. 扫表/索引 → 把需要的 所有列 拷进 sort_buffer

    2. 在内存(或磁盘临时文件)里按排序键快排/归并

    3. 直接返回结果给客户端

  2. 双路排序

    1. 只取 排序键 + 聚簇主键(rowid) 进 sort buffer

    2. 排序后得到“排好序的 rowid 列表”

    3. 按 rowid 顺序回表 取其余列 → 返回


四、如何查看 MySQL 使用了哪一种?

MySQL 不直接写“单路/双路”字样,而是把信息藏在 optimizer traceEXPLAIN FORMAT=json 里。

方法 1:EXPLAIN FORMAT=json(MySQL 8.0 推荐)

EXPLAIN FORMAT=json
SELECT * FROM orders
WHERE order_date >= '2025-01-01'
ORDER BY total_amount DESC LIMIT 20\G

在输出里查找:

"filesort_information": [{"sort_mode": "<sort_key, rowid>"          <-- 双路/* 或 "<sort_key, additional_fields>" */  <-- 单路}
]
  • <sort_key, rowid> → 双路

  • <sort_key, additional_fields><sort_key, packed_additional_fields> → 单路

方法 2:optimizer trace(所有版本通用)

-- 会话级开启
SET optimizer_trace="enabled=on";
-- 执行目标 SQL
SELECT ... ORDER BY ...;
-- 查看 trace
SELECT * FROM information_schema.optimizer_trace\G

搜索关键字:

"filesort_summary": {"sort_mode": "<sort_key, rowid>"
}

含义同上。

方法 3:慢查询日志 / performance_schema(线上无侵入)

  • MySQL 8.0.13+ 的 慢日志 JSON 会记录 "sort_mode" 字段。

  • performance_schema 表 events_statements_history_long 中:

    • SUM_SORT_ROWS 累计排序行数

    • SUM_SORT_ROW_ID > 0 可侧面反映双路排序


五、调优策略速查表

目标手段
避免 filesort建立覆盖索引 (order_col, ...),使 EXPLAIN 出现 Using index
保持单路减少查询列宽度;避免 SELECT *;调大 max_length_for_sort_data
降低内存压力若列过大,可接受双路;或把大 TEXT/BLOB 拆子表延迟加载
加速排序调大 sort_buffer_size(会话级);确保 tmp_table_size/max_heap_table_size 足够

示例调优:

-- 会话级只对当前连接生效
SET sort_buffer_size = 4*1024*1024;          -- 4 MB
SET max_length_for_sort_data = 4096;         -- 允许更长列走单路

六、实战案例

场景:订单宽表 orders 30+ 列,含 TEXT 备注字段。

  1. 初始 SQL:

SELECT * FROM orders
WHERE order_date >= '2025-01-01'
ORDER BY total_amount DESC
LIMIT 20;

EXPLAIN FORMAT=json 看到 "sort_mode": "<sort_key, rowid>",慢日志显示 Sort_row_id: 125000
→ 触发双路+大量回表,耗时 1.2 s。

  1. 优化:

    • 去掉 * 只取需要的 5 列,列宽 < 3 KB

    • 新建复合索引 (order_date, total_amount DESC)覆盖查询列

  2. 结果:

    • EXPLAIN 出现 Using index; Using filesort 消失

    • 查询降至 12 ms,CPU 降 90%。


七、结论

  1. 单路排序 用内存换 I/O,适合小字段;

  2. 双路排序 用 I/O 换内存,适合大字段;

  3. 通过 EXPLAIN FORMAT=jsonoptimizer_trace 查看 sort_mode 即可判定;

  4. 真正的高性能优化是 让排序走索引,彻底告别 filesort。

一句话:看不到 Using filesort,才是 ORDER BY 的终极答案。

http://www.dtcms.com/a/298703.html

相关文章:

  • 面向对象编程实战:Python打造你的数码宠物世界
  • 【速成速通】嵌入式软硬件学习路径:从 0 到实战的知识图谱
  • IPv6实战指南:从接入到应用
  • 《C++ vector 完全指南:vector的模拟实现》
  • Python应用append()方法向列表末尾添加元素
  • 基于Java的健身房管理系统
  • 比特币技术简史 第九章:比特币的未来 - 发展趋势、挑战和机遇
  • 零基础-动手学深度学习-6.1 从全连接层到卷积
  • 使用IP扫描工具排查网络问题
  • 上海AI Lab长时序感知具身导航!StreamVLN:基于慢快上下文建模的流式视觉语言导航
  • 与 TRON (波场) 区块链进行交互的命令行工具 (CLI): tstroncli
  • 为什么会有 CompletableFuture?它是为了解决什么痛点的?
  • Pandas 处理缺失数据
  • 为 GitHub Pages 站点配置自定义域(Windows)(Linked Page)
  • Android Ntp系统校时流程
  • C#(基本语法)
  • 人工智能冗余:大语言模型为何有时表现不佳(以及我们能做些什么)
  • 推荐系统多目标排序模型以及融合策略
  • WebSocket详解
  • ClickHouse 高性能实时分析数据库-物化视图篇
  • 学习笔记《区块链技术与应用》第二天 共识机制
  • 亚马逊阿联酋推“Amazon Bazaar”:解码中东电商市场的本地化突围
  • 线程安全的单例模式
  • 基于米尔瑞芯微RK3576开发板部署运行TinyMaix:超轻量级推理框架
  • 2025年高防IP全景解读:从流量清洗到智能防御的核心跃迁
  • mib2c --生成标量数据对应c文件
  • NOIP普及组系列【2015】 P2669 [NOIP 2015 普及组] 金币题解
  • GPU 驱动安装升级测试
  • 避开算力坑!无人机桥梁检测场景下YOLO模型选型指南
  • Minio Docker 集群部署