自适应哈希索引(ahi)是innodb自动构建的内存加速结构,仅对高频等值查询(=、in)生效,依赖热点索引页访问,受btr_search_latch争用影响,内存占用约buffer pool的1/64。

自适应哈希索引(AHI)不是你建的索引,也不是你能控制的索引——它是 InnoDB 在后台悄悄观察、自动构建、按需淘汰的一层内存加速结构,只对等值查询生效。
它只响应高频等值查询,不处理范围或模糊匹配
AHI 的触发条件非常具体:只有 =、IN 这类精确匹配,且发生在已被频繁访问的 B+ 树索引页上时,InnoDB 才会考虑为其生成哈希条目。像 WHERE name LIKE '%abc'、WHERE age > 25 或 ORDER BY 场景完全绕过 AHI,走原生 B+ 树查找。
常见错误现象包括:明明开了 AHI,但 EXPLAIN 显示查询仍走 full index scan,或者 SHOW ENGINE INNODB STATUS 里 adaptive hash searches 计数长期为 0 —— 很可能就是查询模式不符合触发条件。
- AHI 只基于单个索引页的访问热度,不是整张表或整个索引
- 哈希键是索引键前缀(prefix),长度由实际匹配列数和字节数动态决定,比如联合索引
(a,b,c)上查a=1 AND b=2,哈希键可能是前两列拼接值 - 即使索引存在,若查询未命中“热点页”(比如数据分散在不同 page、访问频率未达阈值),也不会生成对应哈希项
它依赖 btr_search_latch 保护,高并发下可能成瓶颈
AHI 查找本身很快(O(1)),但所有读写操作都要争抢全局锁 btr_search_latch(MySQL 5.7 起已分区,由 innodb_adaptive_hash_index_parts 控制,默认 8 分区)。当大量线程同时执行等值查询(如高并发用户 ID 查询),这个 latch 就可能成为串行点。
典型表现是 SHOW ENGINE INNODB STATUS 中出现大量 waiting for btr_search_latch,或性能监控里看到 innodb_row_lock_time_avg 异常升高,而实际行锁等待并不重。
- 分区数设太高(比如调到 64)会增加内存开销和管理成本;设太低(如 1)则 latch 竞争加剧
- 如果业务以大量简单主键查询为主(如微服务查 user by id),AHI 带来的收益可能被 latch 争用抵消
-
innodb_adaptive_hash_index = OFF后,btr_search_latch完全不参与,适合 OLTP 高并发等值场景压测对比
它不占独立配置内存,但会吃 buffer pool 的 1/64
AHI 结构本身不通过 innodb_buffer_pool_size 外的参数分配,而是在 buffer pool 初始化时预留约 1/64 的空间(MySQL 5.7+ 支持 buffer pool 动态调整,AHI 内存随之 resize)。这意味着:buffer pool 越大,AHI 可用内存越多,能缓存的热点页哈希条目也越多。
但注意:AHI 不是缓存数据,而是缓存「索引键 → 数据页地址」的映射。它不减少 buffer pool 的压力,反而可能因频繁更新哈希表引发额外 CPU 和内存带宽消耗。
- 内存紧张时,AHI 可能因 buffer pool 压力被迫收缩,导致哈希命中率下降
- 无法通过
SHOW VARIABLES直接查 AHI 当前内存占用,需结合SHOW ENGINE INNODB STATUS中的Hash table size字段估算(单位是 bucket 数,每个 bucket 存多个 hash entry) - 关闭 AHI 后,这部分内存自动归还给 buffer pool 使用,无需重启
真正难把握的是它的“自适应”边界:它既不会告诉你哪一页被加了哈希,也不会暴露哈希键的具体构成;你只能通过 adaptive hash searches / adaptive hash search failures 这类统计值反推是否生效。一旦发现查询延迟抖动与 latch 等待相关,或者等值查询在 buffer pool 充足时仍反复读盘,就得把 AHI 开关和分区数拉进调优清单里。











