Hash 索引在MySQL 中使用的并不是很多,目前主要是Memory 存储引擎使用,而且在Memory 存储引擎中将Hash 索引作为默认的索引类型。所谓Hash 索引,实际上就是通过一定的Hash 算法,将需要索引的键值进行Hash 运算,然后将得到的Hash 值存入一个Hash 表中。然后每次需要检索的时候,都会将检索条件进行相同算法的Hash 运算,然后再和Hash 表中的Hash 值进行比较并得出相应的信息。
在Memory 存储引擎中,MySQL 还支持非唯一的Hash 索引。可能很多人会比较惊讶,如果是非唯一的Hash 索引,那相同的值该如何处理呢?在Memory 存储引擎的Hash 索引中,如果遇到非唯一值,存储引擎会将他们链接到同一个hash 键值下以一个链表的形式存在,然后在取得实际键值的时候时候再过滤不符合的键。
由于Hash 索引结构的特殊性,其检索效率非常的高,索引的检索可以一次定位,而不需要像BTree索引需要从根节点再到枝节点最后才能访问到页节点这样多次IO 访问,所以Hash 索引的效率要远高于B-Tree 索引。
可能很多人又会有疑问了,既然Hash 索引的效率要比B-Tree 高很多,为什么大家不都用Hash索引而还要使用B-Tree 索引呢?任何事物都是有两面性的,,Hash 索引也一样,虽然Hash 索引检索效率非常之高,但是Hash 索引本身由于其实的特殊性也带来了很多限制和弊端,主要有以下这些:
1. Hash 索引仅仅只能满足“=”,“IN”和“<=>”查询,不能使用范围查询;
由于Hash 索引所比较的是进行Hash 运算之后的Hash 值,所以Hash 索引只能用于等值的过滤,而不能用于基于范围的过滤,因为经过相应的Hash 算法处理之后的Hash 值的大小关系,并不能保证还和Hash 运算之前完全一样。
2. Hash 索引无法被利用来避免数据的排序操作;
由于Hash 索引中存放的是经过Hash 计算之后的Hash 值,而且Hash 值的大小关系并不一定和Hash 运算前的键值的完全一样,所以数据库无法利用索引的数据来避免任何和排序运算;
3. Hash 索引不能利用部分索引键查询;
对于组合索引,Hash 索引在计算Hash 值的时候是组合索引键合并之后再一起计算Hash 值,
而不是单独计算Hash 值,所以当我们通过组合索引的前面一个或几个索引键进行查询的时
候,Hash 索引也无法被利用到;
4. Hash 索引在任何时候都不能避免表扫面;
前面我们已经知道,Hash 索引是将索引键通过Hash 运算之后,将Hash 运算结果的Hash 值
和所对应的行指针信息存放于一个Hash 表中,而且由于存在不同索引键存在相同Hash 值的可能,所以即使我们仅仅取满足某个Hash 键值的数据的记录条数,都无法直接从Hash 索引中直接完成查询,还是要通过访问表中的实际数据进行相应的比较而得到相应的结果。
5. Hash 索引遇到大量Hash 值相等的情况后性能并不一定就会比B-Tree 索引高;
对于选择性比较低的索引键,如果我们创建Hash 索引,那么我们将会存在大量记录指针信息存与同一个Hash 值相关连。这样要定位某一条记录的时候就会非常的麻烦,可能会浪费非常多次表数据的访问,而造成整体性能的地下。