using filesort是性能断崖的明确信号,表明mysql未用索引排序而需额外内存或磁盘排序;主因包括order by字段无索引、联合索引顺序不匹配、where范围条件中断最左前缀、混合asc/desc方向或函数表达式。

只要EXPLAIN的Extra列里出现Using filesort,说明排序已脱离索引控制,吞吐量会随数据量增长断崖下跌——这不是“可能慢”,而是查10万行时CPU和IO开销翻倍的硬伤。
ORDER BY字段没走索引?先看WHERE条件是否截断最左前缀
索引不是“包含字段就行”,而是结构必须和查询执行路径对齐。比如有索引INDEX (status, created_at),以下情况结果完全不同:
-
WHERE status = 'active' ORDER BY created_at DESC→ ✅ 走索引排序 -
WHERE status > 'active' ORDER BY created_at DESC→ ❌status是范围条件,created_at在索引中已无序 -
WHERE created_at > '2023-01-01' ORDER BY status→ ❌created_at不是最左字段,索引无法定位+排序
关键判断:WHERE中所有等值条件字段,必须构成索引最左连续部分;一旦中间出现范围(>、、<code>BETWEEN、IN),其后的字段仍可用于排序,但再之后的字段就失效了。
MySQL 5.7和8.0对DESC索引的支持差异极大
建索引时写created_at DESC在不同版本效果天差地别:
- MySQL 8.0.12+:
INDEX (status, created_at DESC)能真正支持ORDER BY status, created_at DESC - MySQL 5.7及以前:
DESC声明被完全忽略,索引实际按全ASC存储;但ORDER BY created_at DESC仍可走INDEX (status, created_at)——因为优化器会反向扫描索引,前提是前面全是等值条件 - 混用方向如
INDEX (a ASC, b DESC)配ORDER BY a DESC, b ASC:5.7不认,8.0+也需显式匹配,否则直接退化为filesort
实操建议:查SELECT VERSION()确认版本;5.7环境下别在建索引时写DESC,纯属误导自己。
为什么加了索引还是出现Using filesort?三个高频漏点
索引存在 ≠ 被选用。优化器可能因以下原因主动绕开你的索引:
- 统计信息过期:大批量导入或删除后未运行
ANALYZE TABLE table_name,导致优化器误判成本 - 隐式类型转换:如
WHERE phone = 13800138000而phone是VARCHAR,触发全字段函数转换,索引失效 - ORDER BY用了表达式:哪怕只加个
UPPER(name)或DATE(created_at),索引立即作废,必走filesort
快速验证法:加USE INDEX (idx_name)强制走索引,再跑EXPLAIN。如果Using filesort消失,问题一定出在优化器决策上,而不是索引本身。
多表JOIN后ORDER BY字段来自被驱动表,基本无解?用延迟关联破局
这是最容易被误判的场景:给orders表单独建(total)索引,对SELECT * FROM users u JOIN orders o ON u.id = o.user_id ORDER BY o.total DESC完全无效——MySQL只对驱动表(users)的排序字段尝试索引。
- 错误思路:试图在
users表索引里塞进o.total字段(不可能) - 可行解法:延迟关联——先用
SELECT u.id FROM users u JOIN orders o ON u.id = o.user_id WHERE u.status = 'active' ORDER BY o.total DESC LIMIT 20拿到ID列表,再JOIN补全字段 - 优势:排序阶段只处理主键,IO极小;避免
Using temporary; Using filesort双杀
真正难的从来不是“怎么建索引”,而是确认排序字段是否属于驱动表、是否被WHERE等值条件锚定、以及版本对方向声明的实际支持程度——这三个点漏掉任何一个,建再多索引都是白费。











