1.引言

通过上面两章的学习,我们知道,InnoDB 的主键索引和普通索引都是通过 B+Tree 存储的,叶子节点为数据。那你有没有过这种疑问,InnoDB 索引支持 Hash?

2.解答

对于 InnoDB 的哈希索引,确切的应该这么说:

InnoDB 用户无法手动创建哈希索引,这一层上说,InnoDB 确实不支持哈希索引;

InnoDB 会自调优(self-tuning),如果判定建立自适应哈希索引(Adaptive Hash Index, AHI),能够提升查询效率,InnoDB 自己会建立相关哈希索引,这一层上说,InnoDB 又是支持哈希索引的;

3.举例

那什么是自适应哈希索引(Adaptive Hash Index, AHI)呢?原理又是怎样的呢?咱们先从一个例子开始。

3.1 建表

不妨设有 InnoDB 数据表:

t(id PK, name KEY, sex, flag)

画外音:id是主键,name建了普通索引。

假设表中有四条记录:

1, shenjian, m, A

3, zhangsan, m, A

5, lisi, m, A

9, wangwu, f, B

monogo创建hash索引_主键

如上图,通过前序知识,容易知道 InnoDB 在主键 id 上会建立聚集索引(Clustered Index),叶子存储记录本身,在 name 上会建立普通索引(Secondary Index),叶子存储主键值。

3.2 主键查询

发起主键 id 查询时,能够通过聚集索引,直接定位到行记录。

monogo创建hash索引_自适应_02

3.3 普通索引查询

select * from t where name='ls';

发起普通索引查询时:

(1)会先从普通索引查询出主键(上图右边);

(2)再由主键,从聚集索引上二次遍历定位到记录(上图左边)。

不管聚集索引还是普通索引,记录定位的寻路路径(Search Path)都很长。

3.4InnoDB 建立自适应哈希索引

在 MySQL 运行的过程中,如果 InnoDB 发现,有很多 SQL 存在这类很长的寻路,并且有很多 SQL 会命中相同的页面(page),InnoDB 会在自己的内存缓冲区(Buffer)里,开辟一块区域,建立自适应哈希所有 AHI,以加速查询。

monogo创建hash索引_聚集索引_03

从这个层面上来说,InnoDB 的自使用哈希索引,更像“索引的索引”,毕竟其目的是为了加速索引寻路。

3.5 既然是哈希,key 是什么,value 是什么?

key 是索引键值(或者键值前缀)。

value 是索引记录页面位置。

3.6 为啥叫“自适应(adaptive)”哈希索引?

系统自己判断“应该可以加速查询”而建立的,不需要用户手动建立,故称“自适应”。

系统会不会判断失误,是不是一定能加速?

不是一定能加速,有时候会误判。

3.7 当业务场景为下面几种情况时,AHI 往往是有效的

很多单行记录查询(例如 passport,用户中心等业务)

索引范围查询(此时 AHI 可以快速定位首行记录)

所有记录内存能放得下

3.8 无效场景

当业务有大量 like 或者 join,AHI 的维护反而可能成为负担,降低系统效率,此时可以手动关闭 AHI 功能。

4.总结:

InnoDB 用户无法手动创建哈希索引。

InnoDB 会自调优(self-tuning),如果判定建立自适应哈希索引(Adaptive Hash Index, AHI),能够提升查询效率,InnoDB 自己会建立相关哈希索引。

InnoDB 的自使用哈希索引,更像“索引的索引”,毕竟其目的是为了加速索引寻路。

InnoDB 的 AHIkey 是索引键值(或者键值前缀),value 是索引记录页面位置。