MySQL 8.0 并无独立的 INDEX RANGE SCAN DESCENDING 执行计划类型,其降序扫描能力取决于索引定义是否含 DESC、WHERE 与 ORDER BY 是否匹配最左前缀且方向一致,以及 EXPLAIN 中 key 命中且无 Using filesort;低于 8.0.12 或非 InnoDB 引擎不支持真正降序索引。

MySQL 8.0 的 INDEX RANGE SCAN DESCENDING 并不存在
MySQL 没有像 Oracle 那样显式区分 INDEX RANGE SCAN 和 INDEX RANGE SCAN DESCENDING 的执行计划类型。它的“降序能力”完全依赖于索引定义中是否含 DESC,以及查询的 WHERE + ORDER BY 是否能复用该物理顺序。
你看到的 type: index 或 type: range,配合 Extra: Using filesort 的有无,才是判断是否真正“降序扫描”的唯一依据。
-
EXPLAIN中key字段命中了你建的DESC索引,且Extra里没有Using filesort→ 说明 MySQL 正向扫描了按降序组织的叶子节点,等效于“降序范围扫描” -
key命中但Extra出现Using filesort→ B+ 树无法按需方向连续读取,仍要额外排序 -
key未命中 → 连索引都没走,更谈不上方向问题
WHERE 范围条件会让 ORDER BY 的 DESC 失效
这是最常踩的坑:以为建了 INDEX (a, b DESC),再写 WHERE a > 100 ORDER BY b DESC 就能跳过排序——实际几乎必然触发 Using filesort。
原因在于:B+ 树对前导列 a 做范围扫描时,a > 100 对应多个不连续的数据页;每个页内 b 虽然按 DESC 排,但跨页后整体不再有序。优化器无法保证扫描出来的 b 值是全局降序的。
- ✅ 支持:
WHERE a = 1 ORDER BY b DESC→ 单个索引分支内b严格降序,可直接扫描 - ✅ 支持:
WHERE a IN (1,2) ORDER BY b DESC→ 多个等值分支,各分支内有序,合并后仍需归并,但 8.0 优化器有时能避免filesort(取决于数据分布) - ❌ 不支持:
WHERE a > 1 ORDER BY b DESC→ 几乎一定退化为全索引扫描 +filesort
复合索引中 ASC/DESC 混用的真实约束
不是所有 ASC/DESC 组合都有效。索引的排序能力只覆盖“最左前缀连续、方向一致”的部分。
例如建了 INDEX (a ASC, b DESC, c ASC):
- ✅ 可用于
ORDER BY a ASC, b DESC(前两列方向匹配) - ✅ 可用于
ORDER BY a ASC(只用最左前缀,方向天然一致) - ❌ 不能用于
ORDER BY a ASC, b DESC, c DESC(c方向不匹配) - ❌ 不能用于
ORDER BY b DESC(跳过a,破坏最左前缀)
特别注意:INDEX (a DESC, b ASC) 和 INDEX (a ASC, b DESC) 是两个物理结构完全不同的索引,互不替代。别指望一个索引同时优化 ORDER BY a DESC, b ASC 和 ORDER BY a ASC, b DESC。
版本和存储引擎是硬门槛
DESC 在索引定义中被真正解析并生效,仅限 MySQL 8.0.12+ + InnoDB。低于这个版本,哪怕语法不报错,SHOW CREATE TABLE 里也看不到 DESC,实际仍是升序索引。
- 8.0.11 及更早:
CREATE INDEX idx ON t(a, b DESC)→SHOW CREATE TABLE显示为(a, b),DESC被忽略 - 8.0.12+:同语句 → 显示为
(a, b DESC),且EXPLAIN中能体现效果 - MyISAM、Memory 等引擎:不支持降序索引,即使 8.0 也不认
DESC
真正难的从来不是建个 DESC 索引,而是让 WHERE 条件足够“窄”,把查询约束到单个或极少数索引分支里——否则 B+ 树的物理降序就只是摆设。


















