using filesort表示mysql无法利用索引有序性完成排序,必须额外内存或磁盘排序;根本原因是索引结构与查询模式不匹配,如未满足最左前缀、范围条件截断、升降序不一致或select未覆盖索引字段。

MySQL ORDER BY 性能差,90% 是因为没走索引——不是 SQL 写得不够漂亮,而是索引没对上。
为什么 EXPLAIN 显示 Using filesort 就该警惕
这说明 MySQL 正在把结果集捞进内存(或磁盘临时文件)里手动排序,而不是顺着索引叶子节点顺序读。哪怕只查 10 行,只要没命中索引,它也得先把所有匹配行全读出来再排。
-
Using filesort不代表“一定慢”,但代表“失去控制权”:缓冲区大小(sort_buffer_size)、数据量、是否溢出到磁盘都不可控 - 如果
rows列数值远大于你LIMIT的数量(比如rows=50000但只LIMIT 20),说明排序成本被严重放大 - 注意
key列是否为NULL:没用上索引,ORDER BY就不可能跳过 filesort
多列 ORDER BY 必须匹配联合索引的最左前缀
比如查询是 ORDER BY category, type, code ASC,那索引必须是 (category, type, code) 这个顺序。换成 (type, category) 或 (category, code) 都不行——MySQL 只能利用索引的连续前缀部分。
- 升序/降序也要一致:
ORDER BY a ASC, b DESC无法用(a, b)升序索引(MySQL 8.0+ 才支持混合方向索引) - WHERE 条件会干扰:如果
WHERE status = 'active'且ORDER BY created_at,单列created_at索引可能失效,更适合建(status, created_at) - 别被
SELECT *欺骗:即使ORDER BY字段有索引,如果查询返回大量非索引列,仍可能触发回表,影响整体吞吐
用字符串拼接 sort_key 替代嵌套 CASE WHEN
当业务排序逻辑复杂(比如“未完成任务优先 → 同组内按 category/type/code → 完成但数量异常的次优先”),硬写多个 CASE WHEN 在 ORDER BY 里,不仅难维护,还会让优化器放弃索引路径,强制 Using filesort。
- 把每层规则编码成固定长度字符串,用分隔符拼接:
CONCAT(LPAD(CASE WHEN ... THEN '0' ELSE '1' END, 1, '0'), LPAD(category, 10, '0'), ...) - 确保各字段填充后字典序等价于业务优先级,避免因长度不一导致排序错位(例如
'1'和'10'在字符串比较中顺序不对) - 这个
sort_key字段可以加索引,后续查询直接ORDER BY sort_key,就能走Using index
真正卡住性能的,往往不是排序逻辑本身,而是索引和排序字段之间的“错位”。检查 EXPLAIN 时,先盯住 key 和 Extra,再看 rows——其他都只是补救手段。











