mysql之数据存储模块——B+树系列

为什么要有B+树?

总的来说B+树也是树的一个分支,属于自平衡树,用来存储数据。数据就离不开“增删改查”操作。
关于自平衡树,我们有AVL树红黑树等。他们都是基于“数据位于内存”这样的前提下构建的算法。当面临海量数据时,这些算法将不再适用。并且数据量急剧增多,树的高度增加造成查找时间复杂度O(log(h))也会很大。
基于内存的自平衡树存在的问题:

  • 1.不适用海量数据
  • 2.单个节点存储数据少,导致树的深度过深。查询效率慢。
    B+树采用磁盘预读和多叉树的形式解决!

B树的基本概念

  • 1.所有的叶子结点都在同一层
  • 2.B树定义一个术语:“最小度” t,t的值取决于磁盘块大小page
  • 3.根节点至少包含一个key,除根节点之外的节点至少包含t-1 keys
  • 4.所有的节点(包括根节点)最多只能包含2t-1个节点
  • 5.子节点的数量=当前节点的keys+1
  • 6.和其他自平衡树类似。查找,删除和插入的平均时间复杂度为O(logn)
    最小度 t为3构建的一颗B树
    在这里插入图片描述

B+树

B+树结构
B+树是B树的一个变体,也是一种多路搜索树。

  • 1.B+树的搜索和B树类似,区别是B+树只有到达叶子节点才命中(B树可以在非叶子节点命中)。
  • 2.非叶子节点相当于是叶子节点的索引,所有的关键字都出现在叶子节点的链表中,且链表中的关键字(数据)恰好是有序的;
  • 3.更适合做文件索引系统;

B+树与B树对比

B+树的优势:

  • 1.采用磁盘预读和单一节点存储更多元素的方式,使得查询的IO次数更少。
  • 2.所有的查询最终都会访问到叶子节点,查询性能稳定。
  • 3.所有的叶子结点形成有序链表,便于范围查询。

B树的优势:

  • 如果经常查询的数据靠近根节点,可以考虑B树;

MySQL buffer pool预读机制

预读机制

InnoDB在I/O的优化上有一个比较重要的特性为预读,预读请求是一个i/o请求,它会异步地在缓冲池中预先回迁多个页面,预计很快就会需要这些页面,这些请求在一个范围内引入所有页面。InnoDB以64个page为一个extent。通过设置读取page的数量来触发预读,每次预读取一个extent。在这里插入图片描述
数据库请求数据的时候,会将读请求交给文件系统,放入请求队列中;相关进程从请求队列中将读请求取出,根据需求到相关数据区(内存、磁盘)读取数据;取出的数据,放入响应队列中,最后数据库就会从响应队列中将数据取走,完成一次数据读操作过程。
接着进程继续处理请求队列,(如果数据库是全表扫描的话,数据读请求将会占满请求队列),判断后面几个数据读请求的数据是否相邻,再根据自身系统IO带宽处理量,进行预读,进行读请求的合并处理,一次性读取多块数据放入响应队列中,再被数据库取走

两种预读算法

InnoDB使用两种预读算法来提高I/O性能:线性预读(linear read-ahead)和随机预读(randomread-ahead)

为了区分这两种预读的方式,我们可以把线性预读放到以extent为单位,而随机预读放到以extent中的page为单位。线性预读着眼于将下一个extent提前读取到buffer pool中,而随机预读着眼于将当前extent中的剩余的page提前读取到buffer pool中。

  • 1、线性预读(linear read-ahead)

线性预读方式有一个很重要的变量控制是否将下一个extent预读到buffer pool中,通过使用配置参数innodb_read_ahead_threshold,控制触发innodb执行预读操作的时间。

如果一个extent中的被顺序读取的page超过或者等于该参数变量时,Innodb将会异步的将下一个extent读取到buffer pool中,innodb_read_ahead_threshold可以设置为0-64的任何值(因为一个extent中也就只有64页),默认值为56,值越高,访问模式检查越严格。

mysql> show variables like 'innodb_read_ahead_threshold';
+-----------------------------+-------+
| Variable_name               | Value |
+-----------------------------+-------+
| innodb_read_ahead_threshold | 56    |
+-----------------------------+-------+

例如,如果将值设置为48,则InnoDB只有在顺序访问当前extent中的48个pages时才触发线性预读请求,将下一个extent读到内存中。如果值为8,InnoDB触发异步预读,即使程序段中只有8页被顺序访问。

可以在MySQL配置文件中设置此参数的值,或者使用SET GLOBAL需要该SUPER权限的命令动态更改该参数。

在没有该变量之前,当访问到extent的最后一个page的时候,innodb会决定是否将下一个extent放入到buffer pool中。

2、随机预读(randomread-ahead)

随机预读方式则是表示当同一个extent中的一些page在buffer pool中发现时,Innodb会将该extent中的剩余page一并读到buffer pool中。

mysql> show variables like 'innodb_random_read_ahead';
+--------------------------+-------+
| Variable_name            | Value |
+--------------------------+-------+
| innodb_random_read_ahead | OFF   |
+--------------------------+-------+

由于随机预读方式给innodb code带来了一些不必要的复杂性,同时在性能也存在不稳定性,在5.5中已经将这种预读方式废弃,默认是OFF。若要启用此功能,即将配置变量设置innodb_random_read_ahead为ON。

参考链接:
https://www.geeksforgeeks.org/introduction-of-b-tree-2/
https://mp.weixin.qq.com/s/jRZMMONW3QP43dsDKIV9VQ
https://zhuanlan.zhihu.com/p/27700617

猜你喜欢

转载自blog.csdn.net/weixin_42662358/article/details/106195480
今日推荐