自适应哈希索引(ahi)仅作用于innodb引擎的缓冲池热数据页,不适用于memory表、temporary表等非innodb表;其构建依赖连续相同等值查询模式、页面访问频次≥17次及b+树搜索路径稳定等条件,且仅加速内存中已缓存页的等值查找。

自适应哈希索引不作用于内存表
MySQL 8.0 的自适应哈希索引(AHI)只对 InnoDB 存储引擎的缓冲池(innodb_buffer_pool)中热数据页生效,它不会为 MEMORY 表、TEMPORARY 表或任何非 InnoDB 表构建哈希索引。如果你正在用 CREATE TABLE ... ENGINE=MEMORY,那 AHI 完全不参与——它压根不监听这类表的访问模式。
常见误解是:「既然 MEMORY 表全在内存,再加个哈希索引岂不是更快?」但事实是,MEMORY 表本身已强制使用哈希索引(默认)或 B-tree 索引(显式指定 USING BTREE),其索引结构由建表时决定,且全程驻留内存,不存在“自适应”一说。
InnoDB 表开启 AHI 后等值查询是否真快?
AHI 加速效果高度依赖访问模式,不是所有等值查询都能受益:
- 仅对已加载进
innodb_buffer_pool的索引页有效;若查询触发磁盘 I/O,AHI 不起作用 - 只加速单列或联合索引的最左前缀等值查找(如
WHERE a = ?或WHERE a = ? AND b = ?),对WHERE a = ? AND c = ?(跳过b)无效 -
LIKE 'xxx'(无通配符)可能命中,但LIKE 'xxx%'或LIKE '%xxx'不会触发 AHI 构建 - 二级索引上的 AHI 效果弱于主键索引,因为还需回表,AHI 只加速“找到主键”的那一步
验证是否生效,可查 SHOW ENGINE INNODB STATUS\G 中的 Hash table size 和 used cells,或监控状态变量:Innodb_hash_index_cells_used、Innodb_hash_index_batches。
为什么高并发 JOIN 场景下 AHI 反而拖慢性能?
当多个线程同时执行复杂 JOIN(尤其是多表嵌套、大结果集)时,AHI 的锁竞争会暴露:
- AHI 分区由
innodb_adaptive_hash_index_parts控制,默认为 8;每个分区有独立 latch,但热点索引页仍可能集中在少数几个分区 - 大量线程争抢同一 AHI 分区 latch 会导致
innodb_mutex_spin_waits和innodb_mutex_os_waits显著上升 - 错误日志里可能出现
Waiting for query cache lock类似提示(实际是 AHI latch 等待),但不会直接报错 - 此时关闭 AHI(
SET GLOBAL innodb_adaptive_hash_index = OFF)反而降低延迟抖动
特别注意:innodb_adaptive_hash_index_parts 最大支持 512,但盲目调高未必改善——需结合 SHOW STATUS LIKE 'Innodb%' | grep hash 观察各分区负载是否均衡。
AHI 的内存开销容易被低估
AHI 占用的是 innodb_buffer_pool 内存,不是额外分配。它的结构本身不持久化,但会挤占本可用于缓存数据页的空间:
- 每个 AHI 条目约占用 20–30 字节(含指针、哈希桶元信息),高频热索引页可能生成数万条目
- 如果
innodb_buffer_pool_size已接近物理内存上限,AHI 可能导致更多页面被淘汰,反而增加磁盘 I/O - 没有单独的内存限制参数;无法像
query_cache_size那样精确控制其用量
真正需要警惕的是:AHI 的存在会让 innodb_buffer_pool_pages_data 数值看起来「偏高」,但它反映的是「索引页 + AHI 元数据」混合占用,不能直接等同于有效数据缓存率。











