Adaptive Hash Index(以下简称 AHI)估计是 MySQL 的各大特性中,大家都知道名字但最说不清原理的一个特性。本期图解我们为大家解析一下 AHI 是如何构建的。
随着 MySQL 单表数据量增大,(尽管 B+ 树算法极好地控制了树的层数)索引 B+ 树的层数会逐渐增多; 随着索引树层数增多,检索某一个数据页需要沿着 B+ 树从上往下逐层定位,时间成本就会上升; 为解决检索成本问题,MySQL 就想到使用某一种缓存结构:根据某个检索条件,直接查询到对应的数据页,跳过逐层定位的步骤。这种缓存结构就是 AHI。
AHI 在实现上就是一个哈希表:从某个检索条件到某个数据页的哈希表,仿佛并不复杂,但其中的关窍在于哈希表不能太大(哈希表维护本身就有成本,哈希表太大则成本会高于收益),又不能太小(太小则缓存命中率太低,没有任何收益)。
这就是 AHI(中文名:自适应哈希索引)中"自适应"的用途:建立一个"不大不小刚刚好"的哈希表。
本文主要讨论 MySQL 是如何建立起一个"刚刚好"的 AHI 的,如图 1 所示:需要经历三个关卡,才能为某个数据页建立 AHI,之后的查询才能使用到该 AHI。


我们逐个关卡来介绍:
显而易见,如果我们为了一个很少出现的检索条件建立 AHI,肯定是入不敷出的。
检索条件与索引匹配的列数 第一个不匹配的列中,两者匹配的字节数 匹配的方向是否从左往右进行
如果检索条件是(A1=1 and A2=1),那么此次检索使用了该索引的最左两列,hash info 就是(2,0,true) 如果检索条件是(A1=1), 那么此次检索使用了该索引的最左一列,hash info 就是(1,0,true)
因此我们只能为表中经常被查询的部分数据建立 AHI。所以关卡 3 的任务就是找出哪些数据页是经常被使用的数据页。

表 table1 具有 4 列:A1,A2,A3,B1。具有两个索引 Idx1(A1,A2,A3) 和 Idx2(B1) 关卡 1:选出的索引是 Idx1 关卡 2:选出的 hash info 是 (2, 0, true) (很多查询命中了 Idx1 的最左两列) 关卡 3:选出了某个数据页 P3,其中包含数据 (1,1,1,1) 和 (1,2,2,2) 等等
对于数据(1,1,1,1),根据 hash info,选取前两列建立 AHI 的一项:(1,1)的哈希值->P3 对于数据(1,2,2,2),根据 hash info,选取前两列建立 AHI 的一项:(1,2)的哈希值->P3 以此类推
命中了索引 Idx1 索引 Idx1 上的 hash info 是(2, 0, true),查询条件(A1=1 and A2=2)根据 hash info 转成(1,2)的哈希值 根据此哈希值在 AHI 中查询,可查询到数据页为 P3
随着数据量增大,索引树变得越来越高,查询数据页成本变大 MySQL 引入 AHI 作为查询数据页的缓存,想降低查询数据页的成本 AHI 的"自适应"想解决的问题是 缓存不能太大,也不能太小 AHI 建立的过程中,通过不断限制条件,只为经常使用的索引和经常使用的数据页建立缓存
innodb_adaptive_hash_index_parts。凡是缓存都会涉及多个缓存消费者间的锁竞争。MySQL 通过设立多个 AHI 分区,每个分区使用独立的锁,来减少锁竞争。 SHOW ENGINE INNODB STATUS。其中有 AHI 的每个分区的使用率和 AHI 的命中率。如果你的业务 AHI 使用率过低,理解了 AHI 建立的原理后,就可以分析该业务为何不命中 AHI,来判断业务是否合理,是否需要改变访问模式或者将数据冷热隔离。也可以考虑关闭 AHI,减少 AHI 的维护成本。 在低版本 MySQL 上使用 AHI,先查阅 MySQL bug 列表。低版本是存在一些与 AHI 相关的影响业务的缺陷,在新版本上均已修复,新版本 MySQL 可放心使用。 -The End-
本公众号长期关注于数据库技术以及性能优化,故障案例分析,数据库运维技术知识分享,个人成长和自我管理等主题,欢迎扫码关注。

文章转载自yangyidba,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




