我们都知道MySQL中的B+Tree索引结构,对于根据某个条件查找记录是非常快的。那么,在不断追求极致的驱动下,你有没有想过MySQL会不会有比B+Tree更快的数据结构,来加速查找记录的性能呢?答案是有的,MySQL为了让我们更快地获取自己想查找的记录,在InnoDB中,将查询频繁的条件和索引树结果做了一个Hash映射,这样,一个查询就不需要每次搜索B+Tree去定位结果了,这个Hash映射就叫做AHI,全称Adaptive Hash Index,自适应哈希索引。
一听这名字,你或许已经猜出个一二了。没错!它其实就是一个HashTable,在大学学习《数据结构》的时候,我们都知道Hash Table在查找其中的一个节点的数据是非常快的,算法时间复杂度O(1),所以,相比B+Tree而言,它的查找性能一定是更快的。
但是,有个问题:为什么这个Hash Table叫做自适应哈希索引呢,这个“自适应”是什么概念?
从下面这个案例开始,详细讲解AHI,逐步带你明白AHI这个自适应是怎么一回事?
假设我们交友平台有个功能:筛选出年龄在15到23之间的用户。那么,通常我们会用下面这条SQL实现:
SELECT id, age, sex FROM user WHERE age >= 15 AND age <= 23
同时,我们给user表建了一个索引index_age_sex(age,sex),那么,现在我们再来看看这条SQL是如何使用AHI的?
AHI
既然AHI也是一个HashTable,那首先,你肯定会关心,它的Key是什么样的,Value又是什么样的?那么,我们就先来看看AHI的Key和Value。
我们看到《导读》中的语句的查询条件为age >= 15 AND age <= 23,按照上面我说的AHI的含义:将某一个查询条件和其结果做了一个Hash映射,那么,我们想象中的这个HashTable就类似下面这样:
图中上面的age >= 15 AND age <= 23代表查询条件,也就Key,下面为索引index_age_sex中满足查询条件的4条记录,也就是Value。其中,每条记录的结构为[age,sex,id]。
Key
但是,从上面的图来看,如果查询条件的字段很长,那么,Key存储的空间也就变得很大,对于MySQL这种内存敏感的系统而言肯定是不能接受的,因此,MySQL设计了下面的这种结构来存放Key:
如上图为查找索引index_age_sex时,查询条件为age >= 15 AND age <= 23的结构:
- search_info::n_fields:MySQL使用n_fields来表达查询索引使用到的字段,图中1表示查询条件使用到了索引index_age_sex中的第一个字段,即age。(PS:如果n_fields=2表示查询条件使用到了索引index_age_sex中的age和sex两个字段)。这样做的好处是我们在内存中存储数字就可以表达一个查询条件使用到的索引字段了,更节省存储空间。
- dtuple_t:由于查询条件是一个范围查询,所以,MySQL使用两个dtuple_t结构来表示条件中的两个边界值。如上图,右边第一个dtuple_t中的15表示索引第一列age >= 15,第二个dtuple_t中的23表示索引第一列age <= 23。
最终,MySQL通过search_info::n_fields和dtuple_t的组合来表达查询条件age >= 15 AND age <= 23。如上图中的两个箭头表示的就是这种组合。
讲完Key,我们再来看看MySQL是如何设计HashTable的Value的?
Value
当然,如果按照上面的HashTable的结构,我们肯定认为查询条件age >= 15 AND age <= 23,其在HashTable中的Value就是上面图中1-1中的下面的记录。但是,我们现在来看下面一个场景:
假设现在我将查询条件变为age >= 15 AND a