MySQL InnoDB 缓冲池(Buffer Pool)中 B+ 树索引和自适应哈希索引(Adaptive Hash Index, AHI)的使用场景和区别。
核心概念
1. B+ 树索引(始终使用)
B+ 树是 InnoDB 的默认索引结构,所有数据都通过 B+ 树组织:
┌─────────────────────────────────────────┐
│ 非叶子节点(索引页) │
│ 存储键值 + 指向子节点的指针 │
├─────────────────────────────────────────┤
│ 叶子节点(数据页) │
│ 存储实际数据行 + 指向相邻叶子的指针 │
└─────────────────────────────────────────┘
特点:
- 范围查询友好:叶子节点形成有序链表
- 磁盘友好:节点大小固定(通常 16KB),减少 I/O
- 稳定性能:O(log N) 的查询复杂度
- 支持顺序访问:适合
BETWEEN、ORDER BY等操作
2. 自适应哈希索引(AHI)
AHI 是 建立在 B+ 树之上的内存优化结构,不是替代关系:
查询路径对比:
传统 B+ 树查询: 使用 AHI 加速后:
Root → 非叶子 → 叶子 Hash 直接定位 → 叶子
(3-4 次页访问) (1 次页访问)
使用场景对比
| 场景 | 使用结构 | 原因 |
|---|---|---|
| 所有数据存储 | B+ 树 | 唯一持久化结构,必须存在 |
| 等值查询(=)且高频 | B+ 树 + AHI | AHI 加速热点页访问 |
| 范围查询(>/<) | 仅 B+ 树 | AHI 不支持范围 |
| 全表扫描 | 仅 B+ 树 | 顺序读取,无需索引 |
| LIKE 模糊查询 | 仅 B+ 树 | AHI 无法处理 |
| 联合索引前缀匹配 | 视情况而定 | 前缀不匹配时 AHI 失效 |
AHI 的触发条件
InnoDB 自动为 B+ 树页创建 AHI 条目,当满足:
1. 页被访问多次(成为"热点页")
2. 访问模式是等值查询
3. 该页的访问方式稳定可预测
查看 AHI 状态:
SHOW ENGINE INNODB STATUS;
-- 关注 "INSERT BUFFER AND ADAPTIVE HASH INDEX" 部分
-- 关键指标:
-- - hash searches/s: 使用 AHI 的查询数
-- - non-hash searches/s: 回退到 B+ 树的查询数
配置与优化
# my.cnf 配置
[mysqld]
# 启用/禁用 AHI(默认开启)
innodb_adaptive_hash_index = ON
# 分区数量(减少锁竞争,高并发时有用)
innodb_adaptive_hash_index_parts = 8
关键理解
AHI 不是独立的索引类型,而是 B+ 树的"缓存加速器"
┌─────────────────────────────────────┐
│ SQL 查询层 │
│ SELECT * FROM t WHERE id = 100 │
└──────────────┬──────────────────────┘
▼
┌─────────────────────────────────────┐
│ 优化器决定使用哪个索引 │
│ (基于成本模型选择 B+ 树索引) │
└──────────────┬──────────────────────┘
▼
┌─────────────────────────────────────┐
│ 访问 B+ 树索引结构 │
│ 从根节点开始查找目标页 │
└──────────────┬──────────────────────┘
▼
┌─────────────────────────────────────┐
│ 检查该页是否有 AHI 条目? │
│ ├─ 有 → 直接通过 Hash 定位行 │
│ └─ 无 → 继续在 B+ 树中遍历 │
└─────────────────────────────────────┘
什么时候考虑关闭 AHI?
-- 高并发写入场景,AHI 维护成本可能超过收益
-- 如:大量并发 INSERT/UPDATE 导致频繁 AHI 重组
SET GLOBAL innodb_adaptive_hash_index = OFF;
关闭信号:
SHOW ENGINE INNODB STATUS中non-hash searches远高于hash searches- 观察到
btr_search_latch锁竞争严重
总结
| 问题 | 答案 |
|---|---|
| 数据存在哪里? | 始终在 B+ 树 |
| 等值查询如何加速? | AHI 作为内存中的"快捷方式" |
| 范围查询用什么? | 只用 B+ 树 |
| 能手动创建 AHI 吗? | 不能,完全自适应 |
| 删除 AHI 影响数据吗? | 不影响,只是去掉加速层 |
AHI 是 InnoDB 的透明优化,你不需要(也无法)手动指定使用它,引擎会根据工作负载自动维护。