MySQL中的索引类型

我们平常创建的MySQL表存储引擎大部分是InnoDB,存储引擎的不同决定了数据存储结构的不同。在InnoDB引擎中创建索引可以选择的存储结构有B+树和HASH,默认的存储结构是B+树。

要介绍 B+ 树索引,就不得不提二叉查找树,平衡二叉树和 B 树这三种数据结构。B+ 树就是从他们一步步演化来的。

二叉树

mysql blob字段查询 mysql b+_算法

如图所示,有一个user表的数据有id和namne字段,id是主键,主键是聚集索引。
如果用二叉树存储这个user表的聚集索引,结构就如右图所示。

二叉树的特点是左侧的子节点的值都比父节点小,右侧的子节点的值都比父节点大。
如果我们要查找某一个值,就从顶节点开始查找,这样不会超过数的高度的次数,就能查找到指定的值,效率比全表扫描是要高。

平衡二叉树

上面的二叉树中第一条记录是10,所以生成了上面那样的一棵二叉树,如果id字段里的值是有顺序的,可能就会生成下面这样的二叉树的索引了。

mysql blob字段查询 mysql b+_算法_02

很明显,根据这个索引查找和全表扫描在效率上是没有区别的。

导致这种情况的原因是树的不平衡,所有可以改进一下,在节点插入的过程中,保持二叉树的平衡,平衡的意思是就是每个节点的左右子树的高度差不能超过1。

使用平衡二叉树就可以保证索引的查找次数在一个比较小的范围内了,提高了效率。

B树

使用平衡二叉树存储索引有两个缺点:

  1. 平衡二叉树每个节点只存储一个键值,当数据量特别的大的时候,树的高度也必然很高,查找次数也会很多,影响效率,毕竟每次查找都是一次读盘的操作。
  2. 从磁盘读取数据时是每次读取一个页的数据,如果每次读取只读取一个键值,也是对磁盘的浪费。

基于平衡二叉树的以上两个缺点,将平衡二叉树改进为B树。

mysql blob字段查询 mysql b+_mysql blob字段查询_03

B 树相对于平衡二叉树,有两个改进:

  1. 每个节点(页)存储了更多的键值(key)和数据(data)。
  2. 每个节点拥有更多的子节点,并不只是二叉树了。

基于这两点改进,高度变小了,读取磁盘的次数变少了,索引查找效率就高了。

B+树

B树也有两个缺点:

  1. 非叶子节点既存key也存数据,而每个页大小是固定的,所以每个页中存储的key比较少,数据量大的时候树依然比较高。
  2. 数据不是按顺序存储的,当范围查找、排序查找、去重查找的时候,需要读取多个级别的多个页,效率比较低。

基于以上两个缺点,改进为B+树,B+树如图所示:

mysql blob字段查询 mysql b+_算法_04

1. 非叶子节点只存key不存数据

B+树中,非叶子节点是不存储数据的,只存储key,这样每个页能够存储更多的key,使得树更胖更矮,所以读取磁盘次数更少。假如B+树一个节点可以存储 1000 个键值,那么 3 层 B+ 树可以存储 1000×1000×1000=10 亿个数据,一般根节点是常驻内存的,所以一般我们查找 10 亿数据,只需要 2 次磁盘 IO。

2. 所有数据都存在叶子节点

所有的数据都存在叶子节点,所以数据是按顺序存储的,使得范围查找、排序查找更加方便。

3. B+树的页之间用双向链表连接,数据间用单项链表链接

页之间有双向链表链接,使得扫描数据更加快捷。

聚集索引

上面说的B+树在叶子节点存储数据,这样的索引实际上就是聚集索引,像MySQL里会默认根据主键创建的索引就是聚集索引,根据主键构建一棵B+树,主键所对应的值直接存在叶子节点中。

根据主键查找的意义图如下所示:

select * from user where id>=18 and id <40

mysql blob字段查询 mysql b+_子节点_05

非聚集索引

根据主键意外的字段创建的索引一般都是非聚集索引,非聚集索引也是用B+树构建的,他和聚集索引的唯一不同就是叶子节点中保存的值不是实际的值,而是主键值,找到主键值后再去聚集索引中查找。

举例:
有这样一张表,id是主键,我们在luckyNum字段上创建的非聚集索引。

mysql blob字段查询 mysql b+_算法_06

select * from user where luckNum=33

根据非聚集索引查找过程示意图如下:

mysql blob字段查询 mysql b+_算法_07