using filesort不是错误,而是mysql无法利用索引有序性完成排序,需额外内存或磁盘排序;常见原因包括order by字段未命中索引最左前缀、范围条件截断、混合asc/desc、函数表达式、非驱动表排序或select未覆盖索引字段。

Using filesort不是错误,但说明排序没走索引
Navicat执行计划里出现Using filesort,不代表SQL报错或不能执行,而是MySQL明确告诉你:它得先把符合条件的行捞出来,再在内存或磁盘上额外做一次排序——这个过程不经过索引,纯靠计算资源硬扛。一旦数据量涨到几万行以上,响应时间就可能从毫秒级跳到秒级甚至更长。
ORDER BY字段没被索引覆盖是最常见原因
比如你写SELECT * FROM orders WHERE status = 'paid' ORDER BY created_at DESC,但表上只有status单列索引,created_at单独有索引,却没建联合索引(status, created_at)。MySQL能快速定位status = 'paid'的行,但没法直接按created_at倒序取前N条——它得先扫出所有已支付订单,再排序。
- 联合索引顺序必须匹配查询条件+排序字段:WHERE等值条件字段在前,ORDER BY字段紧随其后
- 如果还有LIMIT,比如
ORDER BY created_at DESC LIMIT 20,联合索引(status, created_at)就能让MySQL直接用索引完成“定位+排序+截断”,彻底避开Using filesort - 注意ASC/DESC一致性:MySQL 8.0+支持混合方向索引(如
(status, created_at DESC)),但5.7及更早版本只对全ASC或全DESC生效;若你用的是旧版本,而查询是ORDER BY created_at DESC,索引定义也得是created_at DESC才有效
隐式类型转换或函数包裹会让ORDER BY失效
哪怕你建了(user_id, updated_at)索引,下面这些写法依然触发Using filesort:
-
ORDER BY CAST(updated_at AS DATE)→ 函数包裹索引字段,索引无法用于排序 -
ORDER BY user_id, updated_at + INTERVAL 1 DAY→ 表达式计算破坏索引有序性 -
ORDER BY user_id, updated_at DESC,但索引是(user_id, updated_at)(默认ASC)→ 方向不匹配,MySQL 5.7不会复用 -
WHERE user_id = 123 ORDER BY updated_at DESC,但索引是(updated_at, user_id)→ 最左前缀不匹配WHERE条件,整个索引可能根本没被选中
覆盖索引能顺便解决filesort,但别强求SELECT *
如果你只需要id和updated_at,而索引是(user_id, updated_at, id),那么SELECT id, updated_at FROM ... WHERE user_id = 123 ORDER BY updated_at DESC不仅能走索引定位+排序,还能触发Using index(只读索引不查表)。但一旦写成SELECT *,MySQL大概率放弃这个优化路径,因为要回表取其他字段,排序成本反而更高——这时Using filesort可能又回来了。
真正容易被忽略的是:ORDER BY字段是否参与了WHERE条件的等值过滤。很多人只盯着“有没有索引”,却没检查“这个索引能不能同时服务WHERE和ORDER BY”。一个没对齐的联合索引,比没有还误导人。











