Using filesort 表示排序未走索引,属严重性能硬伤;需结合 Extra(含 Using filesort)、key(是否为 NULL 或非目标索引)、type(非 index/ALL 且配合 Using index)综合判断,联合索引须严格按等值条件→排序字段→方向一致顺序构建。

EXPLAIN 出现 Using filesort 就代表排序没走索引,不是“有点慢”,是数据量一过万就卡死的硬伤——必须让索引结构和查询模式严格对齐,否则加了索引也白加。
怎么确认是不是真没走索引排序
别猜,直接 EXPLAIN。盯死两列:
-
Extra出现Using filesort→ 没走索引排序,正在额外排序 -
key是NULL或没显示你建的索引名 → 索引压根没被选中
type = index 不等于排序优化成功——它只是全索引扫描,如果 Extra 还有 Using where 或没 Using index,说明仍要回表,排序优势已打折扣。
为什么建了索引还是 Using filesort
常见但容易被忽略的硬伤:
-
WHERE和ORDER BY字段不在同一个联合索引里,比如只在status上建单列索引,却写WHERE status = 1 ORDER BY created_at - 联合索引顺序错:索引是
(created_at, status),但查询是WHERE status = 1 ORDER BY created_at——status不是最左前缀,索引直接被跳过 - MySQL 5.7 及更早版本会忽略
DESC声明,建INDEX (status, created_at DESC)实际按升序存;若查询强制ORDER BY created_at DESC,仍可能触发Using filesort - 字段隐式转换:比如索引是
VARCHAR(255),但ORDER BY用了VARCHAR(100)表达式,或字符集不一致(utf8mb4vsutf8)
怎么建才真正管用的联合索引
核心就一条:等值条件字段放最左,排序字段紧贴其后,方向严格一致。
- 查询是
SELECT id, name FROM users WHERE status = 1 AND type = 'vip' ORDER BY created_at DESC→ 建INDEX idx_status_type_created (status, type, created_at DESC) - 如果有范围条件(如
WHERE status = 1 AND created_at > '2026-01-01'),那ORDER BY只能跟在created_at后面的字段才有效,再后面的列无法参与排序 - 想覆盖查询字段减少回表?把常用
SELECT列加到索引末尾,比如(status, created_at DESC, name, email),但注意TEXT/BLOB字段会让整个索引失效
多表 JOIN 后的 ORDER BY 怎么办
根本原因是 MySQL 默认只对驱动表(FROM 后第一张表)的 ORDER BY 字段尝试索引排序。一旦排序字段来自被驱动表(如 JOIN orders ON u.id = o.user_id ORDER BY o.total DESC),即使 orders 表上有 total 索引,也基本必出 Using filesort。
- 别指望在被驱动表上单独建索引解决这个问题
- 可行路径只有两条:一是改用延迟关联(Deferred Join),先用子查询拿到排序后的主键,再回表补字段;二是把被驱动表的关键排序字段“拉”进驱动表索引(仅当 JOIN 条件强关联、且能预估取值范围时可行)
最容易被忽略的一点:JOIN 后的 ORDER BY,即使驱动表有索引,只要排序字段来源跨表,优化器就大概率放弃索引路径——这不是配置问题,是执行引擎的固有限制。


















