嗨,老铁,欢迎来到我的博客!

如果觉得我的内容还不错的话,可以关注下我在 segmentfault.com 上的直播。我主要从事 PHP 和 Java 方面的开发,《深入 PHP 内核》作者之一。

[视频直播] PHP 进阶之路 - 亿级 pv 网站架构的技术细节与套路 直播中我将毫无保留的分享我这六年的全部工作经验和踩坑的故事,以及会穿插着一些面试中的 考点难点加分点

周梦康 发表于 2015-06-14 6419 次浏览 标签 : Mysql

免费领取阿里云优惠券 我的直播 - 《PHP 进阶之路》

哈希索引(hash index)基于哈希表实现,只有精确匹配索引的所有列的查询才有效。对于每一行数据,存储引擎都会对所有索引列计算一个哈希码,哈希吗是一个比较小的值,不同键值的行计算出来的哈希码也不一样。哈希索引将所有的哈希码存储在索引中,同时哈希表中保存指向每行数据的指针。

在 MySQL中,只有 Memory 引擎显式支持哈希索引。Memory 引擎同时支持 B-trre 索引。值得一提的是,Memroy 引擎是支持非唯一哈希索引的,这在数据库世界里啊敏是比较与众不同的。如果多个列的哈希值相同,索引会以链表的方式存放多个记录指针到同一个哈希条目上。(就和哈希表一样)

CREATE TABLE `testhash` (
  `fname` varchar(50) NOT NULL,
  `lname` varchar(50) NOT NULL,
  KEY `fname` (`fname`) USING HASH
) ENGINE=MEMORY DEFAULT CHARSET=utf8;

mysql> select * from testhash;
+-------+----------+
| fname | lname    |
+-------+----------+
| zhou  | mengkang |
| meng  | zhoukang |
| kang  | zhoumeng |
+-------+----------+
3 rows in set (0.00 sec)

假设索引使用假想的哈希函数 f(),它返回下面的值(都是示例数据,非真实数据):
f('zhou') = 123
f('meng') = 321
f('kang') = 213
实际哈希索引的数据结构如下:
槽(slot) 值(value)
123 指向第一行数据的指针
213 指向第三行数据的指针
321 指向第二行数据的指针
注意每个槽的编号是顺序的,但是数据行不是.
如果现在有如下查询:
mysql> select lname from testhash where fname='meng';
Mysql 先计算'meng'的哈希值,并使用该值寻找对应的记录指针.因为 f('meng') = 321,所以 Mysql 在索引中查找到321,然后通过321对应的是第二行数据的指针,然后再比较第三行的值是否为'meng',以确保就是要查找的行.

哈希索引的限制:
1.只包含哈希值和行指针,不能存储字段值.所以不能使用索引中的值来避免读取行.
2.数据并不是按照索引值顺序存储的,所以不能用于排序.
3.不支持部分索引咧匹配查找,因为哈希索引始终是使用索引列的全部内容来计算哈希值的.
4.仅仅能满足"=","IN"和"<=>"查询,不能使用范围查询。
5.如果哈希冲突的话,存储引擎必须遍历链接中所有的行指针,逐行取比较,知道找到所有符合条件的行.
6.如果哈希冲突的话,索引的维护代价也很高,当从表中删除一行时,存储引擎需要遍历对应哈希值的链表中的每一行,找到并删除对应航的引用.冲突越多,代价越大.

嗨,老铁,欢迎来到我的博客!

如果觉得我的内容还不错的话,可以关注下我在 segmentfault.com 上的直播。我主要从事 PHP 和 Java 方面的开发,《深入 PHP 内核》作者之一。

[视频直播] PHP 进阶之路 - 亿级 pv 网站架构的技术细节与套路 直播中我将毫无保留的分享我这六年的全部工作经验和踩坑的故事,以及会穿插着一些面试中的 考点难点加分点

评论列表