← 返回题目列表

B+ 树索引为什么既能正向扫描也能反向扫描?降序索引还有必要吗?

高频 中等 第 10 / 25 题 更新于 2026/08/03
B+树索引扫描排序降序索引

简化版

B+ 树叶子页按 key 有序并通过链表连接,所以可以从某个位置开始向右做正向扫描,也可以借助双向链表或反向遍历做反向扫描。降序索引的价值在于多列排序方向混合时,让索引顺序更贴合 order by

详细版

单列索引 idx(a) 通常既可支持:

order by a asc
order by a desc

因为叶子记录有序,反向读即可。但联合索引遇到混合方向时更复杂:

order by a asc, b desc

如果索引实际顺序是 (a asc, b asc),在同一个 a 组内 b 是升序,不能直接满足 b 降序。支持降序索引的数据库可以建立 (a asc, b desc),让物理或逻辑索引顺序匹配排序需求,减少额外排序。

因此反向扫描能解决整体方向相反的问题,降序索引更常用于多列排序方向不一致的场景。

完整版教学

一、B+ 树叶子链表为什么适合扫描

B+ 树的数据或索引项都在叶子层有序排列。叶子页之间通过链表连接,范围查询定位到起点后,只要沿叶子链表继续走,就能顺序拿到后续 key。这个结构天然适合 order by 和范围扫描。

如果叶子链表是双向的,反向扫描也很直接:定位到范围末尾或最大 key,然后沿前驱方向往回读。即使实现细节不同,核心都是利用叶子层有序性。

记忆钩子:B+ 树叶子层像一条排好序的街,正着走是升序,倒着走是降序。

二、单列索引为什么通常不怕升降序

对于单列 a,索引顺序是 [1,2,3,4,5]。升序扫描从 1 到 5,降序扫描从 5 到 1。只要能反向读叶子项,就可以避免额外排序。

ASC : 1 -> 2 -> 3 -> 4 -> 5
DESC: 5 -> 4 -> 3 -> 2 -> 1

所以很多场景下,单列降序查询不一定需要专门建降序索引。是否需要仍要看数据库版本、执行计划和存储引擎能力。

三、联合索引的混合排序为什么麻烦

联合索引 (a,b) 默认升序时,排序顺序是先 a 升序,再在相同 a 内 b 升序:

(1,1)
(1,2)
(1,3)
(2,1)
(2,2)
(2,3)

如果查询要 order by a asc, b desc,理想顺序应该是:

(1,3)
(1,2)
(1,1)
(2,3)
(2,2)
(2,1)

这不是简单把整个索引倒着扫能得到的。整个倒扫会变成 a desc, b desc。因此混合方向排序时,降序索引或额外排序就变得重要。

四、降序索引的价值在哪里

降序索引让某些列按降序参与复合 key 排列。这样数据库可以直接按索引顺序输出,避免 filesort 或减少排序成本。它尤其适合高频分页查询,例如按租户过滤后按时间倒序取最新记录。

查询排序合适索引
order by a asc(a) 正扫
order by a desc(a) 反扫
order by a asc,b asc(a,b) 正扫
order by a asc,b desc(a asc,b desc) 更贴合

现代数据库对降序索引支持程度不同,面试时可以先讲原理,再说具体行为要看数据库版本。

五、扫描方向和 where 条件如何配合

B+ 树排序能力通常要和最左前缀一起看。若 where tenant_id=? order by created_at desc limit 20,索引 (tenant_id, created_at) 可以先定位 tenant 的范围,再在该范围内反向扫描最新 20 条。这样不需要扫描全表。

select * from orders
where tenant_id = 7
order by created_at desc
limit 20;

这里关键不是只有 created_at 有序,而是 tenant_id=7 的连续范围内部按 created_at 有序。

六、为什么执行计划仍可能不用索引排序

优化器会做成本估算。如果筛选条件很宽、返回大量行、回表成本高,或者排序列和过滤列组合不合适,数据库可能选择其他执行路径。索引能提供顺序,不代表一定是最低成本。

比如一个二级索引能避免排序,但需要回表 100 万次;全表扫描后内存排序可能反而更便宜。索引排序、覆盖索引、选择性、limit 大小要一起看。

七、常见误区与追问

  • 误区:降序查询一定要建降序索引。 单列或整体方向相反时,反向扫描常常就够。
  • 追问:什么时候降序索引更有意义? 联合索引中多列排序方向混合,或特定数据库需要匹配物理顺序时。
  • 误区:整个索引反扫能得到 a asc,b desc 整体反扫会把前导列方向也反过来。
  • 追问:where a=? order by b desc 怎么利用索引? (a,b) 可定位 a 的范围,再在范围内反向扫描 b。
  • 误区:索引顺序匹配就一定不用排序。 优化器还会考虑回表、行数、limit 和成本。

八、加强记忆

B+ 树叶子层是有序链表,所以正扫升序、反扫降序。单列降序不神秘,倒着读即可;真正麻烦的是联合索引的混合方向,比如 a asc,b desc。降序索引的价值是让复合 key 的内部顺序贴合查询排序。回答这题时把「整体反扫」和「混合方向」分开,基本就讲透了。