MySQL EXPLAIN 中 Using filesort 怎样判断是否需要优化
MySQL 的 EXPLAIN 里看到 Extra: Using filesort,先不要急着把“filesort”理解成一定落盘。它真正表示的是:当前查询不能直接用索引提供 ORDER BY 的顺序,MySQL 需要增加一个排序阶段。小结果集、明确的 LIMIT 或低频后台查询可能完全可以接受;高频接口、排序前要处理大量行时,才值得优先优化。
官方地址:https://dev.mysql.com/doc/refman/8.4/en/order-by-optimization.html
判断是否需要优化,先看排序前要处理多少行、最终返回多少行以及请求频率,再看能否让索引同时服务过滤和排序。只看到 Using filesort 就加索引,容易换来更高写入成本,却没有解决真实瓶颈。
Using filesort 到底说明了什么
在传统格式的 EXPLAIN 中,Extra 出现 Using filesort,说明 MySQL 需要先按连接类型找到满足条件的行,再把排序键和行指针放入排序过程,最后按排序结果取回行。它不是“使用了某个名为 filesort 的文件”,也不直接告诉你排序一定使用磁盘。
MySQL 官方文档把 filesort 定义为额外排序阶段:如果结果集能放进排序缓冲区,排序可以在内存中完成;结果较大时才可能使用临时磁盘文件。因此第一步应该是把它当作“计划中的额外工作”来观察,而不是把标记本身当作故障结论。

用 rows、LIMIT 和频率判断排序成本
我会先把问题拆成“每次排序多少行”和“这条 SQL 多久发生一次”。例如下面的查询,即使 ORDER BY created_at DESC 无法走排序索引,如果过滤后只有几十行且 LIMIT 20,它的排序工作量可能很有限;反过来,过滤条件宽、LIMIT 很大或分页很深时,filesort 才更值得重点排查。
-- 先保留真实查询形状,重点观察 rows、key、Extra 和 LIMIT 的组合 EXPLAIN SELECT id, title, created_at FROM articles WHERE category_id = 12 AND status = 'published' ORDER BY created_at DESC LIMIT 20;
rows 是优化器估算的扫描行数,不是一次运行的精确耗时。判断时至少记录三组信息:过滤后估算行数、最终返回行数、这条 SQL 的调用频率。接口响应慢时,再用适合当前版本的实际执行分析或慢查询观测补充证据;不要把 EXPLAIN 的一个字段当成完整性能结论。
| 观察到的组合 | 优先判断 | 是否立即改索引 |
|---|---|---|
| rows 小、LIMIT 小、调用低频 | 额外排序可能是可接受成本 | 通常不急 |
| rows 大、LIMIT 小但高频 | 每次都在大量候选行中挑前几条 | 优先检查过滤与排序复合索引 |
| rows 大、LIMIT 深或无 LIMIT | 排序结果集本身就很大 | 先缩小结果范围或改变查询形状 |
| 同时出现 Using temporary | 可能还有中间结果物化 | 分开判断临时表与排序原因 |
检查 ORDER BY 能不能和过滤共用索引
索引优化的目标不是让 Extra 看起来更“干净”,而是减少需要扫描和排序的行。假设常用条件是固定的 category_id、status,结果按 created_at 倒序取前 20 条,可以评估让索引覆盖过滤列和排序列的组合:
-- 复合索引的列顺序要对应稳定的过滤条件和排序需求 CREATE INDEX idx_articles_category_status_created ON articles (category_id, status, created_at DESC); -- 建索引后重新查看 possible_keys、key、rows 与 Extra EXPLAIN SELECT id, title, created_at FROM articles WHERE category_id = 12 AND status = 'published' ORDER BY created_at DESC LIMIT 20;
这不是“看到 filesort 就必建此索引”的通用答案。还要检查查询是否真的稳定使用这组条件、字段选择性是否合适、索引是否增加了写入和存储成本,以及是否存在另一条更高频的查询在争用索引设计。若 ORDER BY 包含表达式、不同表的列、无法匹配的前缀,或排序方向与索引形状不适配,MySQL 仍可能保留 filesort。

不能消除 filesort 时,再看排序资源
有些查询天然需要排序,例如按计算表达式排序、需要从较大结果集中取前若干条,或者排序字段无法由可用索引直接提供。此时不要只靠盲目增大 sort_buffer_size。官方建议把它作为排序资源的一部分观察:排序缓冲按需增长;结果过大时可能使用临时磁盘文件;Sort_merge_passes 可以帮助观察临时文件合并次数。
-- 查看排序合并次数,比较同一类查询在调整前后的趋势 SHOW GLOBAL STATUS LIKE 'Sort_merge_passes'; -- 只在确认排序是主要成本后,按会话范围做谨慎实验 SET SESSION sort_buffer_size = 1048576;
如果临时目录空间或磁盘吞吐才是瓶颈,检查 tmpdir 的文件系统容量与并发影响;如果是深分页造成大量无效排序,优先考虑缩小时间范围、使用稳定游标条件或改写业务查询。参数调整只能改变排序资源,不能替代合理的过滤和索引。
可以把最终判断归纳成一条路径:先看 EXPLAIN 是否同时存在大量 rows 与较大的结果范围,再确认 ORDER BY 是否有机会与过滤共用索引,最后才观察排序缓冲、临时文件和合并次数。每次改动后只比较同一查询形状的计划与线上观测,避免把不同 SQL 的结果混在一起。
相关问题
Using filesort 是不是一定使用磁盘?
不是。它表示额外排序阶段;排序可能在内存中完成,结果较大时才可能使用临时磁盘文件。EXPLAIN 本身不区分内存 filesort,需结合优化器跟踪或运行观测判断。
把 ORDER BY 删掉能解决问题吗?
只有业务不要求顺序时才可以删。为了隐藏执行计划标记而改变结果语义,会把性能问题变成业务错误。
增大 sort_buffer_size 就能优化吗?
不一定。它只影响排序缓冲上限,不能减少候选行,也不能让无法匹配的 ORDER BY 自动变成索引排序;应先确认排序是主要成本。
MySQL JSON_SEARCH 怎样按通配符找到 JSON 字符串路径
- 上一篇
- MySQL JSON_SEARCH 怎样按通配符找到 JSON 字符串路径
- 下一篇
- MySQL CTE 怎样避免重复写复杂子查询
-
- 数据库 · MySQL | 43分钟前 |
- MySQL 时间范围查询为什么没有用上索引
- 139浏览 收藏
-
- 数据库 · MySQL | 47分钟前 |
- MySQL 大表分页怎样避免深分页扫描
- 490浏览 收藏
-
- 数据库 · MySQL | 1小时前 | MySQL · 数据库开发 · mysql 递归CTE WITH RECURSIVE cte_max_recursion_depth 层级查询
- MySQL 递归 CTE 怎样设置层级停止条件
- 392浏览 收藏
-
- 数据库 · MySQL | 1小时前 |
- MySQL CTE 怎样避免重复写复杂子查询
- 150浏览 收藏
-
- 数据库 · MySQL | 1小时前 |
- MySQL JSON_SEARCH 怎样按通配符找到 JSON 字符串路径
- 288浏览 收藏
-
- 数据库 · MySQL | 1小时前 | MySQL · JSON · 索引 · 性能 · explain · mysql 索引 JSON json_extract 生成列 JSON_UNQUOTE
- MySQL JSON 字段索引为什么没有命中
- 155浏览 收藏
-
- 数据库 · MySQL | 1小时前 |
- MySQL JSON_EXTRACT 返回带引号怎样处理
- 440浏览 收藏
-
- 数据库 · MySQL | 1小时前 |
- MySQL JSON_STORAGE_FREE 怎样判断部分更新留下的空间
- 347浏览 收藏
-
- 数据库 · MySQL | 1小时前 |
- MySQL 窗口函数怎样计算每组累计金额
- 172浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- PubMedQA
- 深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
- 600次使用
-
- H2O EvalGPT
- H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
- 641次使用
-
- LMArena
- LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
- 673次使用
-
- HELM
- 深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
- 639次使用
-
- MMBench
- MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
- 460次使用
-
- MySQL 明明加了索引,为什么查询还是很慢?先查这 6 个点
- 2026-06-27 374浏览
-
- golang MySQL实现对数据库表存储获取操作示例
- 2022-12-22 499浏览
-
- golang 基于 mysql 简单实现分布式读写锁
- 2023-01-07 384浏览
-
- 详解如何利用GORM实现MySQL事务
- 2023-01-07 184浏览
-
- Go语言实现操作MySQL的基础知识总结
- 2023-01-23 265浏览

