MySQL B-Tree索引、Hash索引和位图索引

发布于 2018-10-01

MySQL B-Tree索引、Hash索引和位图索引

MYSQL最常用的索引结构是BTREE,时间复杂度为O(log(n)),但是总有一些情况下我们为了更好的性能希望能使用别的类型的索引。哈希索引就是其中一种选择。

哈希索引结构的特殊性,其检索效率非常高,索引的检索可以一次定位,不像B-Tree索引需要从根节点到枝节点,最后才能访问到页节点这样多次的IO访问,所以哈希索引的查询效率要远高于B-Tree索引。例如我们在通过用户名检索用户id的时候,他们总是一对一的关系,用到的操作符只是=而已,假如使用hash作为索引数据结构的话,时间复杂度可以降到O(1)。
需要注意的是,目前的mysql版本(5.6)中,只有MEMORY和NDB两种引擎支持哈希索引而我们最常用的INNODB和MYISAM都不支持哈希索引
既然哈希索引的检索效率很高,那为什么大家不都用哈希索引而还要使用B-Tree索引呢,主要是因为哈希索引自身结构的特殊性使得它存在很多的限制。

1、哈希索引的使用场景

a、哈希索引只支持等值比较查询,如:=,in(),<=>(安全比较,比较包含null的时候用),不支持任何范围查询(必须给定具体的where条件值来计算hash值,所以不支持范围查询)。
b、哈希索引数据并不是按照索引列的值顺序存储的,所以也就无法用于排序
c、哈希索引也不支持部分索引列匹配查找,因为哈希索引始终是使用索引的全部列值内容来计算哈希值的。如:数据列(a,b)上建立哈希索引,如果只查询数据列a,则无法使用该索引。
d、哈希索引只包含哈希值和行指针,而不存储字段值,所以不能使用索引中的值来避免读取行(即不能使用哈希索引来做覆盖索引扫描),不过,访问内存中的行的速度很快(因为memory引擎的数据都保存在内存里),所以大部分情况下这一点对性能的影响并不明显。
e、访问哈希索引的数据非常快,除非有很多哈希冲突,当出现哈希冲突的时候,存储引擎必须遍历链表中所有的行指针,逐行进行比较,直到找到所有符合条件的行。
f、如果哈希冲突很多的话,一些索引维护操作的代价也很高,如:如果在某个选择性很低的列上建立哈希索引(即很多重复值的列),那么当从表中删除一行时,存储引擎需要遍历对应哈希值的链表中的每一行,找到并删除对应的引用,冲突越多,代价越大。

2、B-Tree索引的使用场景

a、B-Tree索引支持范围查询,可以被用在像=,>,>=,<,<=和BETWEEN这些比较操作符上。
b、B-Tree索引而且还可以用于LIKE操作符,只要它的查询条件是一个不以通配符开头的常量。
c、由于B-Tree中节点是顺序存储的,可以对查询结果进行order by排序
d、查询必须从索引的最左边的列开始,即索引最左列匹配原则。
e、不能跳过某一索引列。例如,建立组合索引 key(last_name, first_name, birthday),你不能利用索引查找last name为Smith且出生于某一天的人。
f、存储引擎不能使用索引中范围条件右边的列。例如,如果你的查询语句为WHERE last_name=’Smith’ AND first_name LIKE ‘J%’ AND birthday=’1976-12-23’,则该查询只会使用索引中的前两列,因为LIKE是范围查询。

3、位图索引的使用场景

位图索引是一种针对多个字段的简单查询设计一种特殊的索引,适用范围比较小,只适用于字段值固定并且值的种类很少的情况,比如性别,只有男和女,或者级别,状态等等,并且只有在同时对多个这样的字段查询时才能体现出位图的优势。
位图的基本思想就是对每一个条件都用0或者1来表示,如有5条记录,性别分别是男,女,男,男,女,那么如果使用位图索引就会建立两个位图,对应男的10110和对应女的01001,这样做有什么好处呢,就是如果同时对多个这种类型的字段进行and或or查询时,可以使用按位与和按位或来直接得到结果了。

关于自定义哈希索引:

在《高性能的Mysql》这本树中,作者举了一个自定义哈希索引的列子。假设我们在一个表中大量存储了URL,而且需要根据URL来进行查找。因为URL比较长,这个时候如果我们使用B-Tree索引,索引会非常的大。解决的办法是删除原来的URL列索引,而新增一个被索引的列,用来存放URL的哈希值,可以通过CRC32对URL进行计算,并存放在列表中,在查找的时候通过CRC32对url进行计算匹配列表中的hash值。
但是这个地方需要注意hash冲突的问题,所以在查询的时候需要添加url的匹配。例如:where url_crc=CRC32(‘http://www.pieruo.com/p/11564.html’) and url=’http://www.pieruo.com/p/11564.html’。

其它说明:

a、在Mysql中InnoDB引擎有一个特殊的功能叫做自适应哈希索引,他会在内存中基于B-Tree索引的基础上面创建一个哈希索引,这让B-Tree索引也具备了一些哈希索引的优点。
b、B-Tree索引使用语法:unique key unique_username using btree(‘user_name’),这里的using btree 只是显示的指定的使用的索引的方式为B-Tree,对于innodb来说默认的索引方式也是用B-Tree,因此,也可以不写。

喜欢 1
奋楫笃行,臻于至善!

相关文章

使用 Mycat 中间件搭建 MySQL 高可用实现分库分表及读写分离

Mycat 是一款基于阿里开源产品Cobar而研发的开源数据库分库分表中间件(基于Java语言开发),可以用来方便地搭建面向企业应用开发的大数据库集群,支持事务、ACID等特性,其核心是基于代理方案实...
阅读全文

通用架构模式和通用架构服务

架构模式是在给定上下文的软件架构中,针对常发生问题的一种通用、复用的解决方案。架构模式类似于软件设计模式,但是范畴更广。一个好的软件产品往往需要有良好的架构思想和架构服务来支撑整个软件的生命周期,本文...
阅读全文

Java 的可重入锁和不可重入锁

可重入锁又名递归锁,是指在同一个线程在外层方法获取锁的时候,再进入该线程的内层方法会自动获取锁(前提锁对象得是同一个对象或者class),不会因为之前已经获取过还没释放而阻塞。Java中Reentra...
阅读全文

Redis 的两种持久化方式及使用场景分析

Redis是内存数据库,数据都是存储在内存中,为了避免进程退出导致数据的永久丢失,需要定期将Redis中的数据以某种形式(数据或命令)从内存保存到硬盘。当下次Redis重启时,利用持久化文件实现数据恢...
阅读全文

redis 高可用主从,哨兵,集群解决方案

Redis因为其高性能和易用性在我们后端的服务中发挥了巨大的作用,并且很多重要功能的实现都会依赖redis。除了常用的缓存,还有队列,发布订阅等重要用处。所以redis的服务高可用就显得尤为关键。这里...
阅读全文

Redis 缓存穿透、缓存击穿、缓存雪崩的区别及解决方案

Redis缓存的使用,极大的提升了应用程序的性能和效率,特别是数据查询方面。但同时,它也带来了一些问题。其中,最要害的问题,就是数据的一致性问题,从严格意义上讲,这个问题无解。如果对数据的一致性要求很...
阅读全文

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注