索引(Index)是帮助MySQL高效获取数据的数据结构。提取句子主干,就能够获得索引的本质:索引是数据结构。mysql
从MySQL逻辑架构来看,MySQL有三层架构,第一层链接,第二层查询解析、分析、优化、视图、缓存,第三层,存储引擎。算法
索引经过分开查询片,节省了扫描查找时间,大大提高查询效率。sql
大部分数据库系统及文件系统都采用B-Tree或其变种B+Tree做为索引结构。数据库
索引主要在存储引擎层上,不一样的引擎也就有不一样的B-Tree算法。缓存
哈希索引只有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;
这个时候,好比说,用户登录,我须要经过email检索出用户,经过explain获得以下:
mysql> explain SELECT
id
FROMUser
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 | +----+-------------+-------+------+---------------+------+---------+------+--------+-------------+
发现 rows = 384742
也就是要在384742里面进行比对email这个字段的字符串。
这条记录运行的时间是:Query took 0.1744 seconds,数据库的大小是40万。
从上面能够说明,若是直接在email上面创建索引,除了索引区间匹配,还要进行字符串匹配比对,email短还好,若是长的话这个查询代价就比较大。
若是这个时候,在email上创建哈希索引,查询以int查询,性能就比字符串比对查询快多了。
创建哈希索引,先选定哈希算法,这里选用CRC32。
《高性能MySQL》说到的方法CRC32算法,创建SHA或MD5算法是划算的,自己位数都有可能比email段长了。
在表中添加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 ;
这样的话,咱们的SELECT请求就会变成这样:
mysql> SELECT
email_hash
FROMUser
WHERE email_hash = CRC32(“F2dgTSWRBXSZ1d3O@gmail.com”) AND
+----------------------------+------------+ | email | email_hash | +----------------------------+------------+ | F2dgTSWRBXSZ1d3O@gmail.com | 2765311122 | +----------------------------+------------+
在没创建hash索引时候,请求时间是 0.2374 seconds,创建完索引后,请求时间直接变成 0.0003 seconds。
AND email = "F2dgTSWRBXSZ1d3O@gmail.com"
是为了防止哈希碰撞致使数据不许确。
哈希索引也有几个缺点: