mysql索引原理,看这篇就够啦

前言

网上已经有了很多相关mysql索引原理的文章,但是都存在一些问题,有的是直接复制别人的比较老的文章,有的直接开篇讲B+Tree的原理,过程不是很清楚,即使原理讲清楚了,没有各种数据结构的对比也很难体现出B+Tree的优越性,其实我觉得从一些问题来看,然后根据发现问题解决问题的思路来看,这样可能学习效果会更好,所以写了这篇文章,希望你能喜欢

问题列表

1:数据库中最常见的优化方式是什么?

加索引(相信这个大家都知道)

2:为什么加索引能优化慢查询?

。。。。。

3:哪些数据结构可以优化查询速度?

。。。。。

4:这些数据结构都可以优化查询速度,为何mysql会选择B+Tree

。。。。。

不知道没关系,咱们来一一解答

数据库查询过程

对于一般字段而言,mysql查询都是采用的全表扫描的方式来进行数据查询

图片

比如查找

select id from Test where age =1;

扫描第一次就能找到,如果查找

select id from Test where age =7;

可能扫描到第八次才能找到,如果数据非常多,多达几千万行,查找数据最极端的情况下可能需要查找到最后一次才能找到业务所需数据,所以是非常耗时的,我们就需要对数据查找过程进行优化,其实mysql索引就是一种数据结构,来优化查询速度的。方便我们查找数据(包括范围查找和指定查找)

索引的几种数据结构

在这里先给大家介绍一个网站

https://www.cs.usfca.edu/~galles/visualization/Algorithms.html

这个网站可以模拟各种数据结构的插入和查找的动画过程,这样更容易理解

二叉树

二叉树其实就是遵循了一个规律来排列,左小右大

二叉树.png

这样的话比比如我们查询9  通过两次比对就可以查询到

但是二叉树这种数据结构存在一些问题,比如数据是递增或者递减的顺序插入(主键id的确也是这么写入的),二叉树就很容易形成单路链表

如果遇到这种情况那么查找数据就普通的没有加索引的情况没什么区别了

红黑树

红黑树是一种自平衡二叉查找树,平衡二叉树的目的是为了减少二叉查找树层次,提高查找速度 比如依次插入 1到9,二叉树可能就和上图所展示的单路链表一样,红黑树可以自动旋转,减少层数具体过程可以在下面链接中插入看演示https://www.cs.usfca.edu/~galles/visualization/AVLtree.html

散列表(hash)

散列表也为哈希表,又直接寻址改进而来。在哈希的方式下,一个元素k处于h(k)中,即利用哈希函数h,根据关键字k计算出槽的位置。函数h将关键字域映射到哈希表T[0…m-1]的槽位上

散列表的缺点

1)Hash 索引仅仅能满足”=”,”IN”和”<=>”查询,不能使用范围查询。

2)Hash 索引无法被用来避免数据的排序操作。

3)Hash 索引不能利用部分索引键查询。

4)Hash 索引在任何时候都不能避免表扫描。

5)Hash 索引遇到大量Hash值相等的情况后性能并不一定就会比B-Tree索引高。

B树

为了描述B-Tree,首先定义一条数据记录为一个二元组[key, data],key为记录的键值,对于不同数据记录,key是互不相同的;data为数据记录除key外的数据。那么B-Tree是满足下列条件的数据结构:

  • d为大于1的一个正整数,称为B-Tree的度。
  • h为一个正整数,称为B-Tree的高度。
  • 每个非叶子节点由n-1个key和n个指针组成,其中d<=n<=2d。
  • 每个叶子节点最少包含一个key和两个指针,最多包含2d-1个key和2d个指针,叶节点的指针均为null 。
  • 所有叶节点具有相同的深度,等于树高h。
  • key和指针互相间隔,节点两端是指针。
  • 一个节点中的key从左到右非递减排列。
  • 所有节点组成树结构。
  • 每个指针要么为null,要么指向另外一个节点。
  • 如果某个指针在节点node最左边且不为null,则其指向节点的所有key小于v(key1)v(key1),其中v(key1)v(key1)为node的第一个key的值。
  • 如果某个指针在节点node最右边且不为null,则其指向节点的所有key大于v(keym)v(keym),其中v(keym)v(keym)为node的最后一个key的值。
  • 如果某个指针在节点node的左右相邻key分别是keyikeyi和keyi+1keyi+1且不为null,则其指向节点的所有key小于v(keyi+1)v(keyi+1)且大于v(keyi)v(keyi)。

另外,由于插入删除新的数据记录会破坏B-Tree的性质,因此在插入删除时,需要对树进行一个分裂、合并、转移等操作以保持B-Tree性质,而且B-Tree也是不支持范围查找的,所以一般不采用

B+树

B+Tree其实和BTree类似,但是也有很多区别,我们先看图

B+Tree的特征

1:每一个父节点的元素都出现在了子节点中,是节点的最大或者最小元素 比如上面事例图中的元素8和15需要注意的是,根结点的最大元素(这里是15),也是整个B+Tree的最大元素

2:由于父节点的元素都出现在了叶子节点,因此所有的叶子节点包含了全部元素信息,并且每一个叶子节点都带有指向下一个叶子节点的指针,形成了一个有序链表

3:在BTree中,每一个节点都包含了数据,但是在B+Tree中,只有叶子节点包含了数据,中间节点仅仅是索引,没有任何数据关联

注意:聚簇索引(Innodb)的叶子节点包含了整行数据和索引

innodb的索引如图所示

而非聚簇索引(myisam)的叶子节点只包含了索引,而不包含数据行本身 其实从数据库保存文件也能看出来,对于非聚簇索引(myisam)的表来说,数据库保存了三个文件

user_m.frm   表结构定义数据

user_m.MYD   表数据

user_m.MYI   索引文件

myisam索引如图所示

而非聚簇索引(Innodb),数据库只保存了一个文件user_i.frm  所以说他的索引和数据是在一起的。有一个非常形象的例子大家可以理解一下 非聚簇索引(myisam)相当于是一本书前面的目录,咱们可以根据目录去找到对应的内容 而聚簇索引(Innodb)相当于是书每一页下面的页码,页码和书本的内容是在一起的

B+Tree的优势

  1. 在单元素查询的时候,B+Tree会从根节点,逐层向下查找,最终找到要匹配的叶子节点,只需要三次磁盘IO就能找到,这个流程看起来和BTree差不多,其实并不是这样
  • 首先B+树的非叶子节点不包含数据,所以同样的磁盘页可以容纳更多的节点元素,所以相同的数据情况下,B+Tree会显得更加“矮胖”,所以查询磁盘IO的次数会少
  • 另外B+Tree的查询必须最后查找到叶子节点,而B-Tree只要找到了元素即可,不一定必须是得找到叶子节点,所以B-Tree的查询性能很不稳定,B+Tree的查询性能相对稳定很多。
  1. 对于范围查询来说B-Tree非常麻烦,如下图比如我想查找大于3的数据 中序遍历到元素6:中序遍历到元素8:中序遍历到元素9:中序遍历到元素11,遍历结束:这种回环运算非常麻烦 像B+Tree就简单了很多 直接叶子节点链表指过去就行

最后总结一下B+Tree的特征和优势

B+树的特征:


  • 有k个子树的中间节点包含有k个元素(B树中是k-1个元素),每个元素不保存数据,只用来索引,所有数据都保存在叶子节点。



  • 所有的叶子结点中包含了全部元素的信息,及指向含这些元素记录的指针,且叶子结点本身依关键字的大小自小而大顺序链接。



  • 所有的中间节点元素都同时存在于子节点,在子节点元素中是最大(或最小)元素。


B+树的优势:


  • 单一节点存储更多的元素,使得查询的IO次数更少。



  • 所有查询都要查找到叶子节点,查询性能稳定。



  • 所有叶子节点形成有序链表,便于范围查询。


往期精选

redis源码之zset结构的实现

redis源码之set结构

redis源码之hash结构的实现

redis源码之list结构的实现

redis源码之dict

redis源码之SDS

redis的两种持久化的机制,你真的了解么?

绝对能让你彻底明白的Redis的内存淘汰策略

redis缓存穿透穿透解决方案-布隆过滤器

redis五种数据的应用场景

redis中setbit(位操作)的实际应用

扫描二维码

获取更多精彩

微信号 : quven2014

声明:文中观点不代表本站立场。本文传送门:https://eyangzhen.com/239324.html

联系我们
联系我们
分享本页
返回顶部