using filesort 出现在explain中需警惕,因mysql无法用索引排序,须额外内存或磁盘排序,导致io和cpu开销陡增;根本原因是order by字段未被索引覆盖或索引顺序被where非等值条件破坏。

为什么 Using filesort 出现在 EXPLAIN 里就该警惕
它不是报错,但代表 MySQL 没法用索引完成排序,必须把数据捞出来再额外做一次内存或磁盘排序。IO 和 CPU 开销陡增,尤其在 LIMIT 配合大偏移时,性能会断崖下跌。
根本原因通常是:查询的 ORDER BY 字段没被现有索引“覆盖”,或者虽有索引但顺序/范围条件破坏了索引的有序性。
ORDER BY 字段必须是索引的最左前缀,且不能被 WHERE 中的非等值条件截断
比如表有索引 INDEX (a, b, c),以下情况能用上索引排序:
-
WHERE a = 1 ORDER BY b, c→ ✅ 索引连续、等值过滤后剩余字段仍有序 -
WHERE a = 1 AND b > 10 ORDER BY c→ ✅b是范围,但c仍是索引中紧随其后的字段
但这些不行:
-
WHERE a > 1 ORDER BY b→ ❌a是范围,b在索引中已不保证全局有序 -
WHERE b = 1 ORDER BY c→ ❌b不是索引最左字段,索引无法有效定位 + 排序 -
WHERE a = 1 ORDER BY c→ ❌ 跳过了中间字段b,索引(a,b,c)对c单独排序无效
复合索引要按「过滤字段 + 排序字段」顺序创建,别漏掉 SELECT 中的额外字段
如果查询还带 SELECT * 或需要返回其他列,考虑用覆盖索引减少回表。但优先级是:先让排序走索引,再优化返回字段。
例如这个慢查询:
SELECT id, name, created_at FROM users WHERE status = 'active' ORDER BY created_at DESC LIMIT 20;
建索引不能只建 INDEX (created_at) —— WHERE 条件 status 没覆盖;也不能只建 INDEX (status) —— 排序字段没包含。正确做法是:
-
INDEX (status, created_at)→ ✅ 过滤 + 排序都命中 - 如果还要避免回表,且只查这三列,可扩展为
INDEX (status, created_at, id, name)(注意顺序)
注意:DESC 在 MySQL 8.0+ 支持混合升降序索引(如 (status, created_at DESC)),但 5.7 及以前所有索引字段默认同向,ORDER BY created_at DESC 配 INDEX (status, created_at) 依然有效。
EXPLAIN 看懂两处关键输出:没有 Using filesort 且 key 显示用了哪个索引
执行 EXPLAIN 后,重点盯两个字段:
-
key:显示实际使用的索引名。如果是NULL,说明连索引都没走,更别说排序了 -
Extra:里面不含Using filesort,才算真正消除。如果出现Using index condition或Using index,反而是好信号
容易被忽略的一点:如果 ORDER BY 包含多个字段,比如 ORDER BY a ASC, b DESC,而你建的是 INDEX (a, b),MySQL 5.7 会拒绝使用该索引排序(因为不支持混合方向),即使 EXPLAIN 显示用了索引,Extra 里仍可能有 Using filesort —— 这时候得升级 MySQL 或调整查询逻辑。











