using filesort表示mysql无法利用索引天然有序性完成排序,必须额外执行内存或磁盘排序;它出现在explain的extra字段中,是优化器因索引不匹配order by需求而做出的“无奈声明”,常见于order by字段不在索引最左前缀、混合asc/desc、使用函数表达式、join中对非驱动表排序等场景。
using filesort 不代表一定慢,但说明 mysql 没法用索引直接返回有序结果,必须额外排序——这步可能走内存,也可能落磁盘,风险在后者。
Using filesort 出现在 EXPLAIN 的 Extra 字段里意味着什么
它不是错误,而是优化器的“无奈声明”:ORDER BY 所需的顺序,当前索引无法天然提供。MySQL 被迫在查询执行阶段补上排序逻辑,具体用哪种算法(优先队列、快速排序、归并排序)和是否写临时文件,EXPLAIN 看不出来,得结合 sort_buffer_size、结果集大小、是否带 LIMIT 综合判断。
常见触发场景包括:
-
ORDER BY字段不在索引最左前缀位置,比如索引是(a, b),却写ORDER BY b - 混合排序方向,如
ORDER BY a ASC, b DESC,而索引是(a, b)(MySQL 8.0+ 支持降序索引,但老版本不认) - 对字段用了函数或表达式,如
ORDER BY UPPER(name)或ORDER BY created_at + INTERVAL 1 DAY - 排序字段来自非驱动表(JOIN 中的被驱动表),尤其当
ORDER BY含多表字段时
怎么建索引才能让 Using filesort 消失
核心原则:让索引的物理顺序 = ORDER BY 的逻辑顺序,并覆盖 WHERE 条件需要的筛选能力。
例如有查询:SELECT * FROM user WHERE status = 1 ORDER BY created_at DESC LIMIT 20,最优索引是:INDEX (status, created_at)(注意:MySQL 5.7 及以前不支持 DESC 索引方向,所以 created_at DESC 实际仍走升序索引 + 倒序输出,不影响 Using filesort 消除;MySQL 8.0+ 可显式建 INDEX (status, created_at DESC) 提升一致性)。
建索引时注意几个硬约束:
- WHERE 条件中的等值字段(
=、IN)必须放在索引最左,且连续 - 排序字段必须紧接其后,不能跳过中间字段(
INDEX (a, c)无法支撑WHERE a=1 ORDER BY c,因为缺失b导致范围断裂) - 如果
SELECT只查索引字段,可加USING INDEX提效;但若需回表,索引太宽会增加 B+ 树层级和 I/O
为什么加了索引还是出现 Using filesort
不是所有索引都能被排序逻辑复用,以下情况即使有索引也会 fallback 到 filesort:
- 索引字段类型与
ORDER BY表达式不一致,比如索引是INT,但写了ORDER BY CAST(id AS CHAR) - 使用了
UNION,每个子句独立优化,外层ORDER BY无法利用任一子句的索引 -
WHERE条件用了范围查询(>、BETWEEN、LIKE 'abc%'),导致后续索引字段失效 —— 例如索引(a, b, c),WHERE a > 1 ORDER BY b中的b就无法用于排序 - 字符集或排序规则(collation)不匹配,比如列是
utf8mb4_0900_as_cs,但连接中隐式转成utf8mb4_general_ci,索引失效
Navicat 里怎么看 Using filesort 是否真影响性能
Navicat 的“解释”功能只显示 EXPLAIN 结果,不反映真实排序开销。要确认是否真的慢,得结合:
- 执行实际 SQL 并开
PROFILE:SET profiling = 1; SELECT ...; SHOW PROFILES;,看Sorting result阶段耗时占比 - 查
information_schema.PROFILING或启用slow_query_log,设置long_query_time = 0捕获全部语句,观察Rows_examined和Sort_merge_passes(该值高说明频繁归并) - 监控
Created_tmp_disk_tables和Sort_scan这两个状态变量,突增即表明 filesort 正大量落盘
真正麻烦的不是 “出现 Using filesort”,而是它伴随 rows 很大、type 是 ALL 或 index、且没 Using index —— 这时候排序成本才不可控。











