Mysql为什么选用B+Tree 而不选择而二叉树,二叉平衡树,B-Tree结构

335 阅读8分钟

新春祝福

2021 祝大家平安健康,在自己的行业领域深耕有所得,步步高升,早日实现财富自由

关键点

为什么Mysql选择用B+树作为索引结构,而不用其他树结构

二叉树,二叉平衡树,二叉查找树,B-tree ,B+tree ,

数据结构与算法

二分查找法

  • 二分查找法特点:记录有序化递增或递减排序,在查找过程中采用跳跃式方式查找,即先以有序列的中点位置为比较对象,如果要找的元素值小于该点元素,则将查序列缩小为左半部分,否则为右半部分。逐步缩小范围直到找到或找不到该记录为止。

  • 下面给定一组数据(05,13,19,21,37,56,64,75,80,88,92) 看key=21的查找过程。

从图中可以看出,用了3次就找到21这个数字,同样查找88也是3次。如果是顺序查找,找到21需要4次,找到88则需要10次。
对于顺序查找:平均查找次数需要(1+2+3+4+5+6+7+8+9+10+11)/11=6次。而二分查找法为:(12/11) * log2(11+1) -12.9次
二分查找需要1次:56
2次:19,80
3次:05,21,64,88
4次:13,37,75,92
顺序查找的最坏情况是11次,二分查找最坏情况4次。

推导过程

  • 二叉树中序遍历: 左根右,二叉树前序遍历:根左右,二叉树后续遍历:左右根

    • 折半查找过程可以用如图二叉树来描述,通常称为判定树,树中的每个节点表示表中一个记录,节点中的值为该记录在表中的位置,通常称这个描述查找过程的二叉树为判定树,从判定树上可见,查找21的过程是走了一条从根节点到到节点④在判定树上的层次数。因此折半查找在查找成功时进行比较的关键字个数最多不超过树的深度,而具有n个节点的判定树的深度为⌊log2n⌋+1 ,⌊⌋其中为向下取整。判定树非完全二叉树,但它的叶子节点所在层数之差最多为1.则n个节点的判定树的深度和n个节点的完全二叉树的深度相同。
    • 假定有序表长度为n=2^h-1,则折半查找的判定树是深度为h的满二叉树。树中层次为1的节点有1个,层次为2的节点有2个,……,层次为h的节点有2^(h-1)个,假设每个记录的查找概率相等。则查找成功的平均查找长度为如上图ASLbs公式。当n比较大时(n>50) 近似等于 ASLbs= log2(n+1)-1

二叉查找树和平衡二叉树

  • 二叉查找树(二叉排序树)
    • 定义:二叉排序树或是一颗空树;或者具有下列性质的二叉树:(1)若它的左子树不为空,则左子树上所有节点的值均小于它根节点的值;(2)若它的右子树不为空,则右子树上的所有节点的值均大于它的根节点值。(3)它的左右子树也分别为二叉排序树
    • 上面判定树为了描述二分查找设计的一棵树。是二叉查找树比较理想的情况下构造出来的。
    • 但二叉查找树可以任意的构造。同样的的一组数据。也可以有如下的构造树的方式:此时的查找效率和顺序查找差不多,显然这棵二叉查找树的查询效率就低了。因此若想最大性能地构造一棵二叉查找树,就需要这棵二叉查找树是平衡的,从而引出了新的定义----二叉平衡树或称AVL树。
  • 二叉平衡树
    • 定义:二叉平衡树又称AVL树,它或为一棵空树,或者具有下列性质的二叉树:它的左子树和右子树都是平衡二叉树,且左子树和右子树的深度之差的绝对值不超过1.平衡因子BF定义:该节点的左子树和右子树深度之差。
    • 注: BF绝对值为1,0的二叉排序树 极为二叉平衡树。
    • 平衡二叉树的查找性能是比较高的,但不是最高的,最高的性能是建立一棵最优二叉树,但是最优二叉树的建立和维护需要大量的操作,因此,用户只需要建立一棵平衡二叉树即可。
    • 平衡二叉树的查询速度的确很快,但是维护一棵平衡二叉树的代价是非常大的。通常来说,需要1次或多次左或右旋转得到插入或更新后树的平衡性。在一些情况下,维护平衡二叉树可能需要多次的旋转操作。
    • 以上列举了向一棵平衡二叉树插入新的节点,平衡二叉树需要做旋转操作。同理删除和更新,都是通过旋转完成,因此对一棵平衡树的维护是要一定开销的。同时在数据量多的时候树的高度会增加,需要多次I/O操作。

B-Tree和B+Tree

解决平衡二叉树树高问题,减少磁盘I/O

  • B-Tree:B-Tree是一种平衡的多路查找树,在文件系统中应用广泛,一棵m阶的B-Tree,或为空树,或满足下列特性的m叉树
    • (1)树中每个节点至多有m棵子树
    • (2)若根节点不是叶子节点,则至少有两棵子树
    • (3)除根之外的所有非终端节点至少有⌈m/2⌉棵子树
    • (4)每个非终端结点中包含有n个关键字信息: (n,P0,K1,P1,K2,P2,......,Kn,Pn)。其中:
      • a) Ki (i=1...n)为关键字,且关键字按顺序升序排序K(i-1)< Ki。
      • b) Pi为指向子树根的接点,且指针P(i-1)指向子树种所有结点的关键字均小于Ki,但都大于K(i-1)。
      • c) 关键字的个数n必须满足: [ceil(m / 2)-1]<= n <= m-1。
    • (5)所有的叶子节点都出现在同一层次上并且不带信息。

  • 先看一棵阶数为3阶的B-Tree,按照B-Tree的定义,3阶的B-Tree上所有非终端节点至多有两个关键字,至少有一个关键字(即子树个数为2或3)。因此,若关键字个数<=2时,树的深度为2(即叶子节点的层次为2);若关键字个数<=6时,树的深度不超过3,反之若树的深度为4则关键字的个数必须>=7.此时每个节点都含有可能的关键字的最小数目。叶子节点查找不成功的节点为N+1

  • B-Tree的最大深度推导 定义m阶,N个关键字

    • 根据B-Tree的定义,第一层至少有1个节点;第二层至少有2个节点;由于除根之外的每个非终端节点至少有⌈m/2⌉棵子树,则第三层至少有2*(⌈m/2⌉)个节点;……依次类推第l+1层至少有2*(⌈m/2⌉)^(l-1)个节点。而l+1层的节点为叶子节点。则叶子节点查找不成功的节点为N+1,
    • 由此推导 N+1 >= 2* (⌈m/2⌉)^(l-1) , l<=log⌈m/2⌉
    • 最坏情况不超过 l<= log⌈m/2⌉((N+1)/2)+1 在最坏情况下,阶数m越大,深度越低
    • 通过上文可以知道,Mysql每次从磁盘读取数据是按页(Page)计算的,默认为16KB,也可以设置4KB,8KB,而对于存储的最大行数硬性定义为16KB/2-200行,即7992行 ,虽然InnerDB使用的B+Tree ,但假定用B树存储计算逻辑是等同的。m的阶数的计算,可以大致取自磁盘块,每页存储的数据行数。可以得到结论,假定每条数据1k (实际不会这么大)m取16.在对关键字取对数log8计算出来的结果树高也是比平衡二叉树低很多的。
  • B+Tree :从图中可以明显的对比出,B-Tree和B+Tree的区别在于,B+Tree 数据存储于叶子节点上,而B-Tree数据存储在树上每一个节点上。

既然B-Tree 很好的解决了树高的问题Mysql为什么还要选用B+Tree树作为索引结构

  • 在Mysql关系型数据库实用过程中,对于单个记录的查询B-Tree树的效率会比B+树查询效率高,比如查询记录4.B-Tree需要两次I/O,B+Tree需要找到叶子节点,三次I/O。但是对于范围查询来说。比如查找范围1-5的记录,B+Tree,找到1,后续就可以通过叶子节点的双向链表结构,一次找到2,3,4,5.注:虽然有链表结构,但是当想加载到内存的页数据中涵盖不全所有数据范围,会通过页结构中的File Header中FIL_PAGE_PREV,FIL_PAGE_NEXT拿到上页或下页数据,从磁盘读取到内存。 而B-Tree没有向B+Tree一样的链表结构,会增大磁盘I/o

上一篇:InnoDB技术内幕-表的逻辑存储结构 juejin.cn/post/692718…

熊猫笔记邮箱: panda_nodes@163.com