降序索引核心作用是避免多列混合排序时的filesort,而非单纯提速;mysql 8.0中需显式定义如(user_id asc, created_at desc),且仅innodb支持,单列desc查询用升序索引反向扫描即可。

降序索引不是为了“让查询变快”,而是为了“避免 filesort”
很多人一看到“降序索引”,第一反应是“那我 ORDER BY xxx DESC 的时候会更快”。其实不准确。MySQL 5.7 也能用升序索引做 ORDER BY c1 DESC,只是走反向扫描(Backward Index Scan),性能略差但不触发 filesort。真正需要降序索引的,是多列混合排序场景。
比如这个查询:
SELECT * FROM orders ORDER BY user_id ASC, created_at DESC;
如果只建 INDEX idx_user_created (user_id, created_at)(默认全 ASC),MySQL 8.0 会发现:前半段 user_id ASC 匹配,后半段 created_at DESC 不匹配索引顺序 → 触发 filesort。而建 INDEX idx_user_created_desc (user_id, created_at DESC) 后,EXPLAIN 的 Extra 字段就变成 Using index,没有 filesort。
- 关键判断点:看
EXPLAIN输出里有没有Using filesort - 仅单列排序(如
ORDER BY updated_at DESC)时,升序索引 + 反向扫描已够用,降序索引收益极小 - 复合索引中,只要有一列方向不一致(ASC/DESC 混用),且该列在
ORDER BY中非首列,就大概率需要对应方向的索引定义
建表或加索引时,DESC 必须显式写,且只对 InnoDB 有效
MySQL 8.0 的降序索引是 InnoDB 存储引擎原生支持的特性,MyISAM 不认 DESC。建索引时必须显式写出 DESC,不能依赖“默认”或“推断”。
错误写法(看似写了,但没生效):
ALTER TABLE orders ADD INDEX idx_u_c (user_id, created_at) DESC; -- ❌ 语法错误,DESC 位置不对
正确写法:
ALTER TABLE orders ADD INDEX idx_u_c (user_id ASC, created_at DESC); -- ✅ 显式指定每列方向
-
ASC可省略(默认就是 ASC),但DESC绝对不能省 - 用
SHOW CREATE TABLE orders验证:输出里必须看到`created_at` DESC,而不是只有`created_at` - 如果用的是低版本客户端(比如旧版 MySQL Workbench),可能解析不到
DESC,但服务端实际已生效——以SHOW CREATE TABLE为准
降序索引不会影响 INSERT/UPDATE 性能,但会增加一点存储开销
降序索引和升序索引一样,数据变更时都会同步更新 B+ 树节点。InnoDB 对降序键值做了内部转换(比如把时间戳取反再存),所以写入路径没额外负担。
但要注意两点:
- B+ 树页内排序是按你定义的方向来的,所以相同数据量下,降序索引的页分裂模式可能略有不同,不过实践中几乎不可测
- 每个索引项多存一个方向标记位,空间开销可忽略,但如果你建了大量仅用于排序的降序索引(比如几十个
(a,b DESC)变体),累积下来还是有冗余 - 降序索引仍参与统计信息收集(
ANALYZE TABLE),优化器能正确估算其选择性
最容易被忽略的坑:GROUP BY 和 ORDER BY 混用时,降序索引可能不生效
MySQL 8.0 开始,GROUP BY 不再隐式排序。但如果你写:
SELECT user_id, MAX(created_at) FROM orders GROUP BY user_id ORDER BY user_id ASC, MAX(created_at) DESC;
即使有 INDEX (user_id, created_at DESC),优化器也可能不走它——因为 MAX(created_at) 是聚合函数,不是直接字段。这时候得靠覆盖索引或改写为子查询。
另一个常见误判:
- 以为
WHERE a = ? ORDER BY b DESC一定能用上INDEX (a, b DESC)→ 实际可以,但前提是a是等值条件(=或IN),如果是a > ?,那b DESC就失效了 - 在
ORDER BY中用了表达式,比如ORDER BY DATE(created_at) DESC,降序索引完全无效,得用函数索引
降序索引的价值很具体:它只解决“多列排序方向不一致导致的 filesort”这一个问题。别把它当成万能加速器,也别在单列场景强行套用。











