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

Using filesort不是错误,但意味着排序没走索引
它出现在 EXPLAIN 的 Extra 列里,说明 MySQL 没法直接从索引中按顺序读出数据,必须把符合条件的行先捞出来,再额外做一次排序(内存或磁盘)。这不是语法错误,但会吃 CPU、占内存、拖慢查询——尤其当 rows 值大或配合 LIMIT 偏移时,性能断崖下跌。
为什么加了索引还是出现Using filesort
常见错觉是“ORDER BY 字段有索引就行”,实际关键在于:MySQL 必须能用**同一个索引**一次性完成「WHERE 过滤 + ORDER BY 排序」。以下情况会让索引对排序失效:
-
WHERE a > 1 ORDER BY b:a 是范围条件,索引(a, b)中 b 已失去全局有序性 -
WHERE b = 1 ORDER BY a:b 不是最左字段,索引无法定位起始位置 -
WHERE a = 1 ORDER BY c:跳过中间列 b,索引(a, b, c)对 c 无效 -
ORDER BY a ASC, b DESC:MySQL 5.7 及以前不支持混合方向,索引(a, b)全为 ASC 时仍触发 filesort -
SELECT *或返回未被索引覆盖的字段:即使索引结构完美匹配,回表后数据天然无序,排序动作仍会发生
怎么建组合索引才真正管用
核心顺序必须是:等值过滤字段 → 范围过滤字段 → 排序字段,严格连续、不可跳跃。例如:
查询:SELECT id, name FROM users WHERE status = 1 AND age BETWEEN 18 AND 30 ORDER BY created_at DESC
正确索引:INDEX (status, age, created_at)
错误索引:INDEX (status, created_at, age) —— age 范围条件会破坏 created_at 的局部有序性
如果还要避免回表,且只查这三列,可扩展为:INDEX (status, age, created_at, id, name)(注意字段顺序)
容易被忽略的两个硬伤
一是 JOIN 场景下对非驱动表字段排序,比如 JOIN orders o ON u.id = o.user_id ORDER BY o.created_at,即使 o.created_at 有索引,优化器大概率选 users 为驱动表,排序字段来自被驱动表,索引就废了;二是 GROUP BY 在 MySQL 8.0 之前默认隐式排序,哪怕 SQL 没写 ORDER BY,也会触发 filesort —— 这种“看不见的排序”最容易漏掉。











