哈希索引

索引(Index)是帮助MySQL高效获取数据的数据结构。提取句子主干,就能够获得索引的本质:索引是数据结构。mysql

从MySQL逻辑架构来看,MySQL有三层架构,第一层链接,第二层查询解析、分析、优化、视图、缓存,第三层,存储引擎。算法

MySQL逻辑架构

索引经过分开查询片,节省了扫描查找时间,大大提高查询效率。sql

大部分数据库系统及文件系统都采用B-Tree或其变种B+Tree做为索引结构。数据库

索引主要在存储引擎层上,不一样的引擎也就有不一样的B-Tree算法。缓存

 


 

0x01.Hash Index

哈希索引只有Memory, NDB两种引擎支持,Memory引擎默认支持哈希索引,若是多个hash值相同,出现哈希碰撞,那么索引以链表方式存储。数据结构

可是,Memory引擎表只对可以适合机器的内存切实有限的数据集。架构

要使InnoDB或MyISAM支持哈希索引,能够经过伪哈希索引来实现,叫自适应哈希索引。性能

主要经过增长一个字段,存储hash值,将hash值创建索引,在插入和更新的时候,创建触发器,自动添加计算后的hash到表里。优化

直接索引

假若有一个很是很是大的表,以下:spa

CREATE TABLE IF NOT EXISTS `User` ( `id` int(10) NOT NULL COMMENT '自增id', `name` varchar(128) NOT NULL DEFAULT '' COMMENT '用户名', `email` varchar(128) NOT NULL DEFAULT '' COMMENT '用户邮箱', `pass` varchar(64) NOT NULL DEFAULT '' COMMENT '用户密码', `last` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '最后登陆时间', ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

这个时候,好比说,用户登录,我须要经过email检索出用户,经过explain获得以下:

mysql> explain SELECT id FROM User WHERE email = ‘ooxx@gmail.com’ LIMIT 1;

+----+-------------+-------+------+---------------+------+---------+------+--------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+------+---------------+------+---------+------+--------+-------------+ | 1 | SIMPLE | User | ALL | NULL | NULL | NULL | NULL | 384742 | Using where | +----+-------------+-------+------+---------------+------+---------+------+--------+-------------+
  • 1
  • 2
  • 3
  • 4
  • 5

发现 rows = 384742 也就是要在384742里面进行比对email这个字段的字符串。

这条记录运行的时间是:Query took 0.1744 seconds,数据库的大小是40万。

从上面能够说明,若是直接在email上面创建索引,除了索引区间匹配,还要进行字符串匹配比对,email短还好,若是长的话这个查询代价就比较大。

若是这个时候,在email上创建哈希索引,查询以int查询,性能就比字符串比对查询快多了。

Hash 算法

创建哈希索引,先选定哈希算法,这里选用CRC32。

《高性能MySQL》说到的方法CRC32算法,创建SHA或MD5算法是划算的,自己位数都有可能比email段长了。

INSERT UPDATE SELECT 操做

在表中添加hash值的字段:

mysql> ALTER TABLE User ADD COLUMN email_hash int unsigned NOT NULL DEFAULT 0;

接下来就是在UPDATE和INSERT的时候,自动更新 email_hash 字段,经过MySQL触发器实现:

DELIMITER |
CREATE TRIGGER user_hash_insert BEFORE INSERT ON `User` FOR EACH ROW BEGIN SET NEW.email_hash=crc32(NEW.email); END; | CREATE TRIGGER user_hash_update BEFORE UPDATE ON `User` FOR EACH ROW BEGIN SET NEW.email_hash=crc32(NEW.email); END; | DELIMITER ;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

这样的话,咱们的SELECT请求就会变成这样:

mysql> SELECT emailemail_hash FROM User WHERE email_hash = CRC32(“F2dgTSWRBXSZ1d3O@gmail.com”) AND email = “F2dgTSWRBXSZ1d3O@gmail.com”;

+----------------------------+------------+ | email | email_hash | +----------------------------+------------+ | F2dgTSWRBXSZ1d3O@gmail.com | 2765311122 | +----------------------------+------------+
  • 1
  • 2
  • 3
  • 4
  • 5

在没创建hash索引时候,请求时间是 0.2374 seconds,创建完索引后,请求时间直接变成 0.0003 seconds。

AND email = "F2dgTSWRBXSZ1d3O@gmail.com" 是为了防止哈希碰撞致使数据不许确。

 


 

0x02.Hash Index 缺点

哈希索引也有几个缺点:

  • 索引存放的是hash值,因此仅支持 < = > 以及 IN 操做
  • hash索引没法经过操做索引来排序,由于存放的时候通过hash计算,可是计算的hash值和存放的不必定相等,因此没法排序
  • 不能避免全表扫描,只是因为在memory表里支持非惟一值hash索引,就是不一样的索引键,可能存在相同的hash值
  • 若是哈希碰撞不少的话,性能也会变得不好
  • 哈希索引没法被用来避免数据的排序操做
相关文章
相关标签/搜索