自适应哈希索引(Adaptive Hash Index, AHI)是InnoDB存储引擎的核心优化机制,​自动为高频访问的索引页构建内存级哈希表。其核心是绕过B+树遍历​,将多层索引搜索优化为哈希直接定位。

一、最佳实践:什么场景下建议开启?

  • ​读密集型业务​:电商商品查询、用户信息检索等高频点查;
  • ​深层次B+树​:索引高度≥4时;
  • ​MySQL ≥8.0.23环境​:官方修复了关键缺陷;
  • ​内存充足时​:确保Buffer Pool富余(建议>总数据量的30%);

典型场景​
++主键点查(WHERE id=‘n’)++、++二级索引回表(WHERE name=‘xxx’)++、++IN列表查询++
简言之,如果数据库存在高频大表join,且被连接表索引效率较低时,AHI性能提升非常明显。此时建议评估cpu、内存资源,开启AHI。

分享一个案例
执行计划如下,sql略。

+----+--------------------+-------+------------+--------+--------------------------------------------------------------------------------+-------------------------+---------+--------------------------------+--------+----------+-------------------------------------------+
| id | select_type        | table | partitions | type   | possible_keys                                                                  | key                     | key_len | ref                            | rows   | filtered | Extra                                     |
+----+--------------------+-------+------------+--------+--------------------------------------------------------------------------------+-------------------------+---------+--------------------------------+--------+----------+-------------------------------------------+
|  1 | PRIMARY            | ci    | NULL       | ref    | PRIMARY,interview_process_id,resume_screen_init_search,apply_count_union_index | apply_count_union_index | 82      | const                          | 351201 |     0.91 | Using where                               |
|  1 | PRIMARY            | rcl   | NULL       | eq_ref | PRIMARY,idx_code_flag                                                          | PRIMARY                 | 82      | rm_prd.ci.interview_process_id |      1 |    55.14 | Using where                               |
|  1 | PRIMARY            | rrda  | NULL       | ref    | PRIMARY                                                                        | PRIMARY                 | 82      | rm_prd.ci.id                   |      1 |    10.00 | Using where; FirstMatch(rcl)              |
|  4 | DEPENDENT SUBQUERY | rpm   | NULL       | ref    | PRIMARY,manage_index,project_id_index                                          | project_id_index        | 8       | func                           |      3 |    12.70 | Using where                               |
|  4 | DEPENDENT SUBQUERY | rpml  | NULL       | ref    | link                                                                           | link                    | 131     | const,func,rm_prd.rpm.id       |      1 |   100.00 | Using where; Using index; FirstMatch(rpm) |
|  3 | DEPENDENT SUBQUERY | t     | NULL       | ref    | PRIMARY,data_role_find_index,idx_level_link                                    | PRIMARY                 | 50      | rm_prd.ci.dept_id,const        |      1 |     5.00 | Using where                               |
+----+--------------------+-------+------------+--------+--------------------------------------------------------------------------------+-------------------------+---------+--------------------------------+--------+----------+-------------------------------------------+
6 rows in set, 16 warnings (0.01 sec)

开启AHI后测试

root@localhost: 09:58:  [rm_prd]> show variables like 'innodb_adaptive_hash_index';
+----------------------------+-------+
| Variable_name              | Value |
+----------------------------+-------+
| innodb_adaptive_hash_index | ON    |
+----------------------------+-------+
1 row in set (0.00 sec)
# 关闭输出
root@localhost: 10:01:  [rm_prd]> pager cat >>/dev/null
PAGER set to 'cat >>/dev/null'

执行sql耗时:6.38
image.png
关闭AHI后测试

root@localhost: 10:07:  [rm_prd]> show variables like 'innodb_adaptive_hash_index';
+----------------------------+-------+
| Variable_name              | Value |
+----------------------------+-------+
| innodb_adaptive_hash_index | OFF   |
+----------------------------+-------+
1 row in set (0.00 sec)
# 关闭输出
root@localhost: 10:09:  [rm_prd]> pager cat >>/dev/null
PAGER set to 'cat >>/dev/null'

执行sql耗时:12.29
image.png
开启与关闭AHI时,explain输出的执行计划完全一致,但sql耗时差了2倍。

二、副作用

<1> DDL成本升高
删除超过32GB缓冲池的大表时,AHI清理需扫描BP的flush_list链表,导致实例Hang住。

规避方法:

  • MySQL ≥8.0.23版本已修复此问题
  • 5.7版本需手动在删表前关闭AHI
SET GLOBAL innodb_adaptive_hash_index=OFF;  
-- 执行DROP TABLE操作  
SET GLOBAL innodb_adaptive_hash_index=ON;  

<2> 高并发下的锁竞争
旧版MySQL(<5.7)使用全局锁btr_search_latch,高并发时CPU争用飙升。

规避方法:
升级到≥5.7版本,启用分区锁(innodb_adaptive_hash_index_parts,默认8分区)。另外监控信号量,若SHOW ENGINE INNODB STATUS出现大量btr0sea.c的RW-latch等待,需调高分区数或关闭AHI。

诊断innodb状态:

show engine innodb status\G;

image.png

调大分区数:

# 经实测,调大分区后,cpu使用率下降明显。
SET GLOBAL innodb_adaptive_hash_index_parts = 32;  -- 如将分区数从8提升至32

<3> AHI收益小于开销

  • 当数据库低频查询较多,热点数据较少时,AHI的构建成本高于受益;
  • 索引页频繁变动时,数据修改触发AHI维护开销(如页分裂时重构哈希)。

三、结论:开还是不开?​​

MySQL 在 ​8.4 LTS 版本中已将自适应哈希索引(AHI)的默认状态从 ON 改为 OFF。可见官方态度更倾向提供可预测的性能基线,而非依赖动态优化带来的不确定性。

由于在写操作频繁或高负载环境下可能出现的性能瓶颈,使得AHI功过参半,所以开与不开需要DBA根据实际环境做出决策。

  • 推荐开启的场景​:MySQL≥8.0.23、读多写少、内存充足、B+树层次深
  • 谨慎使用的场景​:5.7版本且需频繁删大表、超高频写操作、内存紧张

image.png
欢迎关注作者公众号:类MySQL学堂

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐