explain出现using filesort代表排序未走索引,是数据量过万即明显卡顿的硬伤;根本原因是索引结构与查询模式不匹配,如order by字段顺序跳过索引中间列、起始列不一致、含函数或表达式、范围条件后接排序字段、混合asc/desc(mysql 5.7及以前)、多表join中order by引用被驱动表字段等。

EXPLAIN里出现Using filesort就代表排序没走索引
这不是“可能慢”,是数据量一过万就明显卡顿的硬伤。MySQL 只有两种排序路径:一是直接从索引中按顺序读出结果(Using index),二是把数据捞出来再额外排序(Using filesort)。后者会占用 sort_buffer,撑爆后写磁盘临时文件,I/O 开销陡增。
ORDER BY字段顺序不匹配索引最左前缀
索引 (a, b, c) 的物理存储是先按 a 升序、a 相同时再按 b 升序、b 也相同时再按 c 升序。只要 ORDER BY 跳过中间列(如 ORDER BY a, c),或起始列不一致(如 ORDER BY b),索引就无法提供有序输出。
-
WHERE status = 1 ORDER BY created_at→ 索引(status, created_at)有效 -
WHERE category = 'A' ORDER BY created_at→ 即使有(created_at)单列索引,也触发Using filesort -
WHERE status = 1 AND created_at > '2023-01-01' ORDER BY updated_at→created_at是范围条件,其右侧的updated_at无法用于排序
混合ASC/DESC或对字段加函数
MySQL 5.7 及之前完全不支持反向索引扫描。哪怕你建了 INDEX (user_id, pay_time DESC),查询写成 ORDER BY user_id ASC, pay_time DESC,优化器仍会忽略索引排序能力。
- MySQL 8.0.12+ 支持混合方向,但必须显式建索引:
CREATE INDEX idx ON t (a ASC, b DESC) -
ORDER BY UPPER(name)、ORDER BY a + b、ORDER BY DATE(created_at)→ 索引值 ≠ 计算值,直接失效 -
SELECT *即使ORDER BY id,也会因回表破坏主键顺序,导致Using filesort
多表JOIN时ORDER BY引用被驱动表字段
MySQL 只对驱动表(FROM 后第一张表)的 ORDER BY 字段尝试走索引排序。一旦排序字段来自被驱动表(如 JOIN orders o ON u.id = o.user_id ORDER BY o.total),即使 orders 表上有 (total) 索引,也必然触发 Using filesort。
- 错误解法:给被驱动表单独建索引 → 无效
- 可行解法:用延迟关联(先查驱动表主键排序,再回表补字段)
- 覆盖思路:在驱动表上建含 JOIN 键 + 被驱动表排序字段的复合索引(需 WHERE 条件能命中最左前缀)
Using filesort 就藏在 EXPLAIN 里等你发现。











