Mysql优化(1):索引原理-B+树

什么是索引

    首先,我们经常会听到一个说法:怎么对mysql进行优化。十个里有九个半会说:加索引,索引优化啊。确实,对mysql进行优化,最有效、最能解决问题、最普遍的方式就是设计合适的索引,正确的索引能够将查询效率提升好几个数量级。为什么索引能够显著提升查询效率呢,我们从索引结构来一点点讨论。
    索引是什么,从mysql官方文档来说:索引是帮助Mysql高效获取数据的排好序的数据结构!
这里有两个重点:排好序数据结构,什么是数据结构:就像链表,数组,树形,图这样用来组织存储数据的方式。而Mysql索引用的是一种叫做B+树的数据结构来存储数据的,而且这样存储的数据是有序的。那又延伸出是B+树的概念了,为了理解这个,我们先弄清楚二叉树的概念

二叉树

Mysql优化(1):索引原理-B+树_第1张图片
有一张有两列col1、col的表 t 如上图。为col2列建立索引,右边就是一个二叉树,它的特点是:

  1. 非叶子节点最多有两个子节点
  2. 节点右边的数据>=节点数据
  3. 节点左边的数据<节点数据

假设我现在要查找 col2=77 的数据,从根节点开始找,要查找3次,路径为34 --> 89 --> 77。如果数据总量为N,那么最多需要查找的次数为log2N。但是mysql最终没有采用二叉树来做为索引的结构,为什么呢?我们来考虑以下情形:如果为col1列建立索引呢,它是一个自增序列。那么构建出来的二叉树就是这样的。

在这里插入图片描述
它变成了一个单向链表,查询数据得进行全表扫描。如果有100万行数据,它最多就可能会找100万次,这个效率是不可接受的。
所以二叉树作为索引结构是不合适的。那又提出了第二种方案:红黑树(也叫平衡二叉树)

红黑树

红黑树,Red-Black Tree 「RBT」是一个自平衡(不是绝对的平衡)的二叉查找树(BST),它是自平衡的,它不会出现上面那样一条线的链表结构。
Mysql优化(1):索引原理-B+树_第2张图片
有新数据插入时,它会根据自身的情况进行自平衡,让自己始终保持一个二叉树的形状。它最终也没有被Mysql采用,主要是因为:

  1. 如果数据量过大,几百万甚至千万级别,那么树的深度可能达到20以上, 在这里插入图片描述
    数据量达到200万的时候,已经需要搜索20次以上了。也就意味着20次的磁盘I/O,这个开销太大了。
  2. 自平衡的代价过大,例如一个20层的红黑树结构,新增了一个在第二层的数据,那么后面的18层结构都要变动,代价太大。
    那有没有更好的办法呢!这就开始谈到B树了(不是B+树)

B树(B Tree)

上面的红黑树不合适的主要原因就在于当数据量达到百万级时(这是实际数据的常见情况,数据量不过万的情况下没必要建索引)树的深度过高。那我们就想办法降低树的高度?怎么做呢。。。。。。。
好伤脑筋啊,怎么办?log2N的复杂度已经很可以了,还怎么减少树高度呢!
对了!我们可以增加树的宽度,也就是将树进行横向拓展,没必要说每层只有一个节点啊,多放几个节点不就ok了吗!就像这样
Mysql优化(1):索引原理-B+树_第3张图片
这就是B树,它的主要特点是:

  1. 叶子节点具有相同的深度,叶子节点的指针为空
  2. 所有索引元素不重复
  3. 节点中的数据从左到右递增排列。

每个节点由两部分组成:指针项和数据存储项(data部分)
指针指向下一个节点,数据项存储索引所在行除了索引列之外的数据。
如果一层有1000个节点,那么三层结构能够存储的数据量可以达到1000*1000*1000=10亿,这个数据量完全能满足我们的需要!然而这个结构有两个缺陷:

  1. 每层的最大大小(页大小)在MySql中是固定的:16Kb。如果一个表的列数很多:那么每一行的数据量(除索引列之外的所有列的数据)就比较大,可能达到1Kb。那么每层能存储的节点数可能就不到16个。这样就大大降低了查询效率!
  2. 实际查询中,我们除了等于条件查询外,更多的是范围查询 a

B+ 树(B+ Tree)

    由此产生了 B+ 树,它是 B树的变种。

Mysql优化(1):索引原理-B+树_第4张图片
它有以下特点:

  1. 非叶子节点不存储data数据,只存储索引,可以横向放置更多的数据。
  2. 叶子节点包含所有索引字段
  3. 叶子节点用指针连接,提高区间访问的性能,并且最后一个叶子节点和第一个节点之间也有一个指针,形成一个闭环。

现在我们来算算三层的 B+数能放多少数据。以索引字段为bigInt类型为例:bigInt类型占 8Bytes,索引结构占 6Bytes。
每层最大大小为 16Kb(通过InnodbPageSize参数配置,不建议自行修改该数据,可能造成不可测的后果)。第一层可以放
16Kbytes/14Bytes=1170个数据项。
第三层是放具体数据的,data的大小不固定,我们取大的值吧。假设一个表有100个字段(这个数量已经尽量夸大了),平均字段长度为8Bytes ( int为4Bytes, bigInt为8Bytes,float为4Bytes, double为8Bytes) ,一行的数据量为800Bytes,我们以 1Kbytes计算好了,那么第三层每个节点可以存放16Kb/1Kb=16个数据。

    三层结构可以存储 1170*1170*16=21902400个数据。2000多万!我们已经尽量低估三层结构所能存储的数据量了。也就是说2000万的数据量,加了索引之后只要三次查找就可以查找到数据。
我们也注意到,因为数据只存储在叶子节点上,哪怕这个数据就在第一个的位置上,我们还是要经过三次查找才能找到数据。索引数据量如果很少,建索引反而会降低效率!

你可能感兴趣的:(MySql优化,数据库&SQL)