MYSQL索引数据结构为什么使用B+树?
MYSQL索引数据结构为什么使用B+树?
常见 的数据存储结构
Hash
hash的存储格式(java中data数据量大时可转红黑树)
缺点:
- 这种存储方式对hash算法要求会比较高(当hash碰撞频率较高时,需要对链表数据中的值进行遍历),且数据查询时,需要将所有数据拿到内存中查询,对内存压力较大。
- 企业级应用中范围查找频率较高,乱序的存储对范围查找不友好。
二叉树(BST)
描述:
- 左子树不为空时,左子树节点小于根节点的值
- 右子树不为空时,右子树节点大于根节点的值
- 节点的左右子树也分别是二叉查找树
- 没有键值相等的节点
缺点:
极端情况下,二叉树会退化成链表
平衡二叉树(AVL)
描述:
- 与二叉树相比,所有节点的左右子树高度差不超过1。
- 不管我们是执行插入还是删除操作,只要不满足上面的条件,就要通过旋转来保持平衡,而旋转是非常耗时的。
由此我们可以知道AVL树适合用于插入删除次数比较少,但查找多的情况
红黑树
描述:
- 红黑数要求每条最长路径不长于最短路径的两倍,如果大于两倍就要进行旋转
- 任意一条路径上黑色节点数量一致
- 插入和查询时数据时间上基本上保持一致
缺点:
随着数据量的增加,节点数越来越多,树会越来越深。无论二叉树还是红黑树,都会因为树的深度过深而造成io次数变多,影响数据读取的效率。
B树
描述:
-
排序方式:所有节点关键字是按递增次序排列,并遵循左小右大原则;
-
子节点数:非叶节点的子节点数>1,且<=M ,且M>=2,空树除外(注:M阶代表一个树节点最多有多少个查找路径,M=M路,当M=2则是2叉树,M=3则是3叉);
-
关键字数:枝节点的关键字数量大于等于ceil(m/2)-1个且小于等于M-1个(注:ceil()是个朝正无穷方向取整的函数 如ceil(1.1)结果为2);
-
所有叶子节点均在同一层、叶子节点除了包含了关键字和关键字记录的指针外也有指向其子节点的指针只不过其指针地址都为null对应下图最后一层节点的空格子;
B树相对于平衡二叉树的不同是,每个节点包含的关键字增多了,特别是在B树应用到数据库中的时候,数据库充分利用了磁盘块的原理(磁盘数据存储是采用块的形式存储的,每个块的大小为4K,每次IO进行数据读取时,同一个磁盘块的数据可以一次性读取出来)把节点大小限制和充分使用在磁盘快大小范围;把树的节点关键字增多后树的层级比原来的二叉树少了,减少数据查找的次数和复杂度;
B+树
描述:
-
节点合并规则:当前是要组成一个5路查找树,那么此时m=5,关键字数必须大于等于ceil(5/2)(这里关键字数<2就要进行节点合并);
-
满足节点本身比左边节点大,比右边节点小的排序规则;
-
关键字数小于二时先从子节点取,子节点没有符合条件时就向向父节点取,取中间值往父节点放;
B+树是B树的一个升级版,相对于B树来说B+树更充分的利用了节点的空间,让查询速度更加稳定,其速度完全接近于二分法查找。为什么说B+树查找的效率要比B树更高、更稳定;我们先看看两者的区别。
-
B+跟B树不同B+树的非叶子节点不保存关键字记录的指针,只进行数据索引,这样使得B+树每个非叶子节点所能保存的关键字大大增加;
-
B+树叶子节点保存了父节点的所有关键字记录的指针,所有数据地址必须要到叶子节点才能获取到。所以每次数据查询的次数都一样;
-
B+树叶子节点的关键字从小到大有序排列,左边结尾数据都会保存右边节点开始数据的指针。
-
非叶子节点的子节点数=关键字数(来源百度百科)(根据各种资料 这里有两种算法的实现方式,另一种为非叶节点的关键字数=子节点数-1(来源维基百科),虽然他们数据排列结构不一样,但其原理还是一样的Mysql 的B+树是用第一种方式实现);
B+树相对于B树的优点是:
-
B+树的层级更少:相较于B树B+每个非叶子节点存储的关键字数更多,树的层级更少所以查询数据更快;
-
B+树查询速度更稳定:B+所有关键字数据地址都存在叶子节点上,所以每次查找的次数都相同所以查询速度要比B树更稳定;
-
B+树天然具备排序功能:B+树所有的叶子节点数据构成了一个有序链表,在查询大小区间的数据时候更方便,数据紧密性很高,缓存的命中率也会比B树高。
-
B+树全节点遍历更快:B+树遍历整棵树只需要遍历所有的叶子节点即可,,而不需要像B树一样需要对每一层进行遍历,这有利于数据库做全表扫描。
B树相对于B+树的优点
如果经常访问的数据离根节点很近,而B树的非叶子节点本身存有关键字其数据的地址,所以这种数据检索的时候会要比B+树快。
我们为什么要选择用B+树而不是B树呢的简单说法
因为B树不管叶子节点还是非叶子节点,都会保存数据,这样导致在非叶子节点中能保存的指针数量变少(有些资料也称为扇出)
指针少的情况下要保存大量数据,只能增加树的高度,导致IO操作变多,查询性能变低;