ahi在高并发二级索引更新、缓冲池不足或范围查询为主时易引发buf_pool_mutex争用、哈希失效频繁及资源浪费,建议通过监控指标判断后全局关闭。

高并发二级索引更新时AHI会争抢buf_pool_mutex
当业务频繁执行 UPDATE 或 DELETE 涉及二级索引(如 WHERE status = 'processing'),InnoDB 需反复调整索引页结构,同时触发 AHI 的重建逻辑。此时 AHI 维护线程会与用户线程竞争 buf_pool_mutex,表现为 SHOW ENGINE INNODB STATUS 中出现大量 waiting for buffer pool mutex。这不是锁等待,而是内存池全局互斥锁争用,直接卡住所有缓冲池操作。
实操建议:
- 监控
Innodb_mutex_spin_waits和Innodb_buffer_pool_wait_free,若二者同步持续升高,且Innodb_hash_searches_full占比低于 0.2,说明 AHI 几乎没帮上忙,反而在添堵 - 关闭前先确认写负载中点查比例:如果
SELECT ... WHERE key = ?少于总查询 30%,AHI 基本不生效 - 避免只在压测时关——生产环境的突发写高峰(如订单状态批量更新)更容易暴露这个问题
缓冲池不足 + 高频页淘汰导致AHI反复构建失效
当 innodb_buffer_pool_size 明显小于活跃数据集(例如热数据 20GB,但 buffer pool 只配了 8GB),索引页频繁进出内存。AHI 依附于 Buffer Pool 中的页存在,页一被淘汰,对应哈希条目就失效;新页一加载,又得重新探测、构建——这个过程要反复获取 btr_search_latch,把原本分散的 latch 争用集中到少数几个页上。
实操建议:
- 检查
SHOW STATUS LIKE 'Innodb_buffer_pool_pages_%',若free长期低于 5%,且flushed持续上涨,说明页淘汰压力大 - 观察
SHOW ENGINE INNODB STATUS输出里Hash table size行后是否频繁出现node heap has X buffer(s)—— 这是哈希节点高频分配/释放的明确信号 - 不要指望调大
innodb_adaptive_hash_index_parts来缓解:它只分摊 latch,不解决页级热点本身;在 buffer pool 不足的前提下,加分区反而增加管理开销
混合负载中范围查询占比高但AHI仍被强制启用
AHI 对 BETWEEN、ORDER BY、LIMIT、LIKE 'abc%' 等查询完全无效,但它依然在后台消耗 CPU 和内存资源维护哈希表。尤其当业务是「读多写少但读以范围为主」(如后台报表导出、分页列表),AHI 不仅不加速,还挤占 buffer pool 内存,间接导致真实数据页命中率下降。
实操建议:
- 用
pt-query-digest抽样分析慢日志,统计type字段为range、index、ALL的查询占比;若超过 60%,AHI 收益极低 -
Innodb_hash_searches与Innodb_hash_searches_full的比值长期低于 0.3,就是 AHI 效率低下的硬指标 - 关闭后注意观察
Innodb_buffer_pool_read_requests是否上升——若上升不明显,说明原本的点查本来就不依赖 AHI,关得对
无法按表或按查询禁用,只能全局开关
有人试图用 /*+ NO_HASH_INDEX */ 注释,或 SET SESSION innodb_adaptive_hash_index = OFF,这些全部无效。innodb_adaptive_hash_index 是纯 GLOBAL 变量,没有 SESSION 级别实现,也没有 SQL hint 支持。它作用于整个 InnoDB 引擎,所有表共享同一套哈希结构。
实操建议:
- 动态关闭用
SET GLOBAL innodb_adaptive_hash_index = OFF,但要注意:已建立连接不会立即丢弃已有哈希条目,只是停止新增;新连接才完全不受影响 - 生产环境更推荐写死配置文件:
innodb_adaptive_hash_index = OFF加入my.cnf并重启 MySQL,避免因连接复用导致行为不一致 - 切勿在高峰期执行
SET GLOBAL—— 虽然不锁表,但会触发内部哈希表清理,短时可能加剧 latch 争用











