where + order by 复合索引列序必须为:先所有等值条件列,再排序列;范围查询后列无法用于排序,否则触发using filesort。

能,但必须严格按最左前缀顺序组织索引列,且避免范围查询截断后续列的使用。
WHERE + ORDER BY 复合索引的列序怎么排?
顺序必须是:先所有等值条件列(WHERE col = ?),再排序列(ORDER BY)。不能颠倒,也不能把排序列插在中间。
- 正确示例:
WHERE user_id = 100 AND status = 'paid' ORDER BY created_at DESC→ 索引应为(user_id, status, created_at) - 错误示例:
WHERE user_id = 100 ORDER BY status, created_at→ 若索引是(user_id, created_at, status),则status在created_at后,无法用于排序(因created_at是范围/非等值时会截断) - 若
WHERE中有范围条件(如created_at > '2025-01-01'),它之后的列**完全不能用于排序优化**,哪怕写在索引里
为什么加了复合索引,EXPLAIN 还显示 Using filesort?
常见原因不是没建索引,而是索引没被“完整命中”:
-
WHERE条件跳过了最左列(如索引(a, b, c),却只用WHERE b = 1)→ 索引失效 -
ORDER BY方向与索引方向不一致(如索引是(a, b)升序,却ORDER BY a ASC, b DESC)→ MySQL 8.0+ 支持混合方向,但老版本仍触发Using filesort - 查询中用了函数或表达式:
ORDER BY UPPER(name)或WHERE DATE(created_at) = '2025-01-01'→ 索引列被计算,直接失效 - SELECT 的字段太多,导致无法走覆盖索引,MySQL 认为回表成本高,干脆放弃用索引排序
如何验证索引是否真正消除了排序开销?
看 EXPLAIN 输出里的两个关键字段:
-
type应为ref或range(不是ALL或index) -
Extra中**不能出现**Using filesort,理想状态是Using index(覆盖索引)或至少Using where; Using index - 执行时观察
Sort_merge_passes状态变量是否为 0(SHOW STATUS LIKE 'Sort_merge_passes';)
注意:即使 Extra 没写 Using filesort,如果 key 显示用了索引但 rows 很大,说明索引过滤性差,排序数据量仍不小——这时候得回头检查等值列的选择性,而不是只盯着排序本身。











