Mysql高性能索引系列二:哈希索引

今天我们来学习一下hash索引,我们常用的索引都是基于B-Tree,hash索引我们使用的不多,但是在某些场景下也是一个不错的解决方案。

hash索引的工作原理:只有匹配索引所有列的查询才有效。对于每一行数据数据,存储引擎都会对所有的索引列计算一个hash code,hash code是一个较小的值,并且不同的键值行计算出来的hash code也不一样。哈希索引将所有的哈希码存储在索引中,同时在哈希表保存指向每个数据行的指针。(memory引擎支持非唯一hash索引,在多个列的哈希值相同,索引会以链表的方式存放多个记录指针到同一个哈希条目中。)

Mysql高性能索引系列二:哈希索引_第1张图片

每个槽的编号是顺序的,但是数据行却不是。

索引过程:

SQL:select * from table where name = 'Peter';

1、首先计算Peter的hash值,hashcode('Peter') = 8784

2、在索引中查找8784,找到了“指向第三行的指针”

3、比较第三行的值是否为Peter

因为索引自身只需要存储对应的哈希值,所以索引的结构时分紧凑,这也让哈希索引查找的速度非常快。

限制:

哈希索引只包含哈希值和行指针,而不存储字段值,所以不能使用索引的值来避免读取行,不过,访问内存中的行速度很快,所以大部分情况下这一点对性能影响不大。

哈希索引数据并不是按照索引值顺序存储的,所以也就无法用于排序

不支持部分索引列匹配查找,因为哈希索引始终是使用索隐裂的全部内容来计算哈希值的,例如:在数据列(A, B)上简历哈希索引,如果查询只有数据列A,则无法使用该索引

只支持等值比较查询,包括(=、IN()、<=>),也不支持任何范围查询,例如where price > 100

访问哈希索引的数据非常快,除非有很多哈希冲突(不同的值,通过hash算法算出相同的hash值),当出现哈希冲突的时候,存储引擎必须遍历链表中所有的行指针,逐行进行比较,直到找到所有符合服务器条件的行

如果哈希索引冲突很多的话,一些索引维护操作的代价也会很高。例如,如果在某个选择性很低(哈希冲突很多)的列上建立哈希索引,那么当从表中删除一行时,存储引擎需要遍历对应哈希值中的每一行,并找到删除对应的行引用,冲突越多,代价越大。

InnoDB下的hash索引的使用:

在B-Tree基础上创建一个伪哈希索引,这和真正的哈希索引不是一回事哦,因为还是使用B-Tree进行查找,但是它使用哈希索引值而不是键本身进行索引查找。需要我们在查询的where子句中手动指定使用哈希函数

使用触发器的方式维护一个哈希索引列:

Mysql高性能索引系列二:哈希索引_第2张图片
Mysql高性能索引系列二:哈希索引_第3张图片

如果采用这种方式,记住不要使用SHA1()和MD5()作为哈希函数。因为这两个函数计算出来的哈希值是非常长的字符串,会浪费大量空间,比较式也会比较慢。这两个函数是强加密函数,设计目标是最大限制消除冲突,但这里并不需要这样高的要求。简单的哈希函数的冲突范围可以被接受,同事也能提供更好的性能。

当出现哈希冲突的时候,查询的写法:

SELECT id FROM usehash WHERE url_crc=CRC32("http://www.mysql.com") AND url="http://www.mysql.com";

冲突情况下,以下查询是无法正常工作的

SELECT id FROM usehash WHERE url_crc=CRC32("http://www.mysql.com");

演示一下吧:


Mysql高性能索引系列二:哈希索引_第4张图片
错误写法:
Mysql高性能索引系列二:哈希索引_第5张图片
正确写法
Mysql高性能索引系列二:哈希索引_第6张图片

你可能感兴趣的:(Mysql高性能索引系列二:哈希索引)