B+ 树索引和 Hash 索引有什么区别?
简化版
Hash 索引适合等值查询,能通过哈希值快速定位桶;但它不维护 key 的有序性,所以不适合范围查询、排序、前缀匹配和最左前缀这类有序访问。B+ 树索引维护 key 的有序结构,等值查询略多走树高,但能支持范围扫描、排序和分页,是数据库通用索引的主力。
详细版
B+ 树索引按 key 有序组织,查找时从根走到叶子,复杂度通常是 O(log_f n),其中 f 很大,所以树高很低。Hash 索引把 key 计算成 hash 值,再定位桶,等值查询在理想情况下接近 O(1)。但 hash 后的值不保留原始大小关系,age BETWEEN 20 AND 30、ORDER BY age、LIKE 'abc%' 都无法靠 Hash 索引顺序扫描。
因此选型不是谁绝对更快,而是看查询模式。只有大量精确等值查询且不需要排序范围时,Hash 索引才有明显优势;业务数据库默认更常用 B+ 树,因为它覆盖等值、范围、排序和组合索引等更多场景。
完整版教学
一、两种索引的核心差异
B+ 树索引保存的是有序 key 空间,Hash 索引保存的是 key 到 hash bucket 的映射。一个保留顺序,一个打散顺序。这个差异决定了它们的适用范围。
B+ tree:
10 -> 20 -> 30 -> 40 -> 50 有序
Hash index:
hash(10)=7
hash(20)=2
hash(30)=9
hash 后桶位置不再代表大小关系
所以 Hash 索引在等值查询上很直接,但一旦问题涉及“大于、小于、排序、连续扫描”,它就缺少结构信息。
二、等值查询谁更快
理想情况下,Hash 索引等值查询可以接近 O(1):计算 hash,定位桶,检查桶内候选 key。B+ 树等值查询要走树高,例如根页、内部页、叶子页,复杂度是 O(log_f n)。但数据库里的 f 很大,树高通常只有 3 到 4 层,所以 B+ 树等值查询也很快。
| 查询 | B+ 树索引 | Hash 索引 |
|---|---|---|
id = 100 | 支持,走根到叶 | 很适合 |
age BETWEEN 20 AND 30 | 支持,定位起点后扫叶子链 | 不适合 |
ORDER BY age | 可利用有序性 | 不适合 |
name LIKE 'abc%' | 可能支持前缀范围 | 通常不适合 |
这张表是面试回答的主干:Hash 的优势很窄,B+ 树的覆盖面更广。
三、为什么 Hash 不适合范围查询
范围查询依赖 key 的大小关系。Hash 函数的目标恰恰是把输入均匀打散,让相近 key 分布到不同桶。比如 20、21、22 的 hash 值可能分别落到 8、1、15 号桶,无法顺着桶连续扫描得到 [20,30]。
key: 20 21 22 23
hash: 8 1 15 3
key 连续,不代表 bucket 连续
因此 Hash 索引查范围时往往只能退化成扫描更多数据。B+ 树则不同,叶子层按 key 排序,找到 20 后沿链表扫到 30 即可。
四、组合索引和最左前缀的差异
B+ 树组合索引按字典序组织,例如 (a,b) 的顺序先按 a 排,再在相同 a 内按 b 排。因此它能支持 a = 1、a = 1 AND b > 10 这类最左前缀访问。Hash 组合索引通常是对组合 key 整体做 hash,缺少前缀有序性。
B+ tree index (a,b):
(1,1), (1,5), (1,9), (2,1), (2,3)
可支持:
a = 1
a = 1 AND b BETWEEN 3 AND 9
这也是为什么数据库面试里经常把 B+ 树索引、联合索引、最左前缀放在一起问。它们本质都依赖有序结构。
五、Hash 冲突和稳定性问题
Hash 索引还要处理冲突。不同 key 可能映射到同一个 bucket,桶内需要链表、数组或其他结构存放候选项。冲突少时很快,冲突多时性能会下降;如果 hash 函数或数据分布不好,还可能出现热点桶。
bucket 5:
key=12 -> rowA
key=99 -> rowB
key=203 -> rowC
查询 key=99:
先定位 bucket 5,再比较桶内原始 key
B+ 树也有页分裂等维护成本,但它的有序性让范围、排序、分页更稳定。真实数据库选索引结构时,不只看平均复杂度,还看查询能力和最坏情况下的行为。
六、常见误区与追问
记忆钩子:Hash 快在等值,B+ 树强在有序。
- 误区:Hash 索引 O(1),所以一定比 B+ 树好。 Hash 主要适合等值查询,范围和排序能力弱,通用性不如 B+ 树。
- 误区:Hash 索引能支持
>、<范围条件。 Hash 打散顺序,无法按 key 连续扫描。 - 误区:B+ 树只能做范围查询,等值查询不快。 B+ 树树高很低,等值查询也很稳定。
- 追问:为什么联合索引最左前缀依赖 B+ 树? 因为组合 key 按字典序排列,只有从最左字段开始才形成连续区间。
- 追问:Hash 冲突怎么处理? 桶内保存多个候选项,查询时还要比较原始 key,冲突多会降低性能。
- 追问:什么时候考虑 Hash 索引? 大量精确等值查询、不需要范围排序,并且存储引擎支持时可以考虑。
七、加强记忆
B+ 树和 Hash 索引的根本区别是“是否保留顺序”。Hash 把 key 打散,等值查询路径短,但范围、排序、前缀和联合索引能力弱;B+ 树按 key 有序,点查要走几层树,但能覆盖等值、范围、排序和分页。面试回答不要只喊 O(1) 或 O(log n),要落到具体 SQL 访问模式:等值看 Hash,通用索引和范围排序优先看 B+ 树。