explain显示走索引但ahi未生效,是因为查询未命中“热点索引页”、非纯等值条件(如like、范围查询)、联合索引前缀不匹配、buffer pool过小或刚启动,导致innodb未为其生成哈希条目。

innodb_adaptive_hash_index 默认开启,但它不是“总能加速”的银弹——它只在特定等值查询模式下生效,且可能因锁争用拖慢高并发场景。
什么时候EXPLAIN显示走索引但AHI完全没用?
常见错误现象是:SQL写了WHERE id = 123,EXPLAIN显示type=ref、用了主键索引,但SHOW ENGINE INNODB STATUS里adaptive hash searches计数长期为 0,Hash table size也很小。
原因很直接:
- 查询未落在被InnoDB判定为“热点”的索引页上——比如数据分散在上百个不同 page,单页访问频次不够阈值(内部约每 10 次索引查找中触发 1 次)
- 查询条件不是纯等值:
WHERE name LIKE 'abc%'、WHERE age > 30、ORDER BY created_at全部绕过 AHI,哪怕索引存在 - 联合索引前缀不匹配:对
(a,b,c)建索引,却查WHERE b = 2 AND c = 3,无法生成哈希键 - buffer pool 太小或刚启动不久,AHI 内存区域尚未填充,
Hash table size仍为初始极小值
btr_search_latch争用是怎么把QPS拉垮的?
AHI 查找快,但所有读写操作(包括普通 SELECT、UPDATE、INSERT)都要短暂持有btr_search_latch才能决定是否走哈希路径。这个 latch 在 MySQL 5.7+ 被分成了innodb_adaptive_hash_index_parts个分区,默认 8 个。
但问题出在:当大量线程同时做主键点查(如微服务查user_id),latch 分区数不足时,会出现明显串行等待:
-
SHOW ENGINE INNODB STATUS中反复看到waiting for btr_search_latch -
innodb_row_lock_time_avg异常升高,但Innodb_row_lock_waits几乎没变——说明不是行锁,是 latch 卡住 - 关闭 AHI 后压测,QPS 可能提升 20%~40%,尤其在 buffer pool 命中率已很高的 OLTP 场景
怎么判断当前该开还是该关innodb_adaptive_hash_index?
别猜,看三项实时指标:
- 查
SHOW ENGINE INNODB STATUS\G,关注Hash table size(真实占用桶数)和node heap(链表节点数)——若长期size 且 <code>node heap = 0,说明 AHI 几乎没被激活 - 对比
adaptive hash searches和hash searches per second与select full range join或select range的比值:若前者占比 - 观察
innodb_buffer_pool_read_requests与innodb_buffer_pool_reads—— 若 buffer pool 命中率 > 99%,AHI 加速价值本就有限;反之若命中率低,AHI 对热点页的 O(1) 定位才更关键
关闭后要注意什么?
关掉innodb_adaptive_hash_index = OFF很简单,但效果不是全局“变慢”或“变快”,而是移除一个潜在瓶颈点:
- 所有等值查询回归原生 B+ 树遍历,深度为 3~4 层的索引影响微乎其微;但深度 ≥5 的二级索引回表可能多 1~2 次内存页访问
-
btr_search_latch完全退出执行路径,高并发点查吞吐更稳,延迟毛刺减少 - 内存释放给 buffer pool 其他用途——AHI 占用约 buffer pool 的 1/64,关掉后这部分自动归还,不需重启
- 注意:MySQL 8.0.23+ 修复了部分 latch 争用逻辑,若你用的是这个版本之后,先调大
innodb_adaptive_hash_index_parts(比如设为 16),再评估是否关闭











