电子说
本文大概字数三千多,预计观看时长十分钟,练习时长两个半小时。希望大家都能学到知识。
不少网友看 B+ 树,看不懂树结构什么意思。希望本文可以帮你理解树结构生成的过程。
在说 B+ 树之前,需要知道,一页的大小是多少。
show global status like 'innodb_page_size'
MySQL一页16kb
这个是看出,一页是 16384 也就是16384/1024 = 16kb
innodb 中一页的大小默认是 16kb。
基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能
- 项目地址:https://github.com/YunaiV/ruoyi-vue-pro
- 视频教程:https://doc.iocoder.cn/video/
创建表结构 指定引擎为 Innodb。
CREATE TABLE tree(
id int PRIMARY key auto_increment,
t_name VARCHAR(20),
t_code int
) ENGINE=INNODB
查看一下当前表的索引情况
show index from tree
B 树和 B+ 树的显示都是 BTREE,但是实际使用的 B+ 树。B+ 树也是 B 树的升级版,这里显示为 B 树也是没有问题的。
BTREE创建数据,这里会有一个小知识点,如果看过上一篇文章的朋友可以明白是为什么。
INSERT into tree VALUES(3,"变成派大星",3);
INSERT into tree VALUES(1,"变成派大星",1);
INSERT into tree VALUES(2,"变成派大星",2);
INSERT into tree VALUES(4,"变成派大星",4);
INSERT into tree VALUES(7,"变成派大星",7);
INSERT into tree VALUES(5,"变成派大星",5);
INSERT into tree VALUES(6,"变成派大星",6);
INSERT into tree VALUES(8,"变成派大星",8);
插入测试数据为什么创建数据的时候数据是乱序的,但是在创建好数据,被排好顺序了。
我们在寻找答案之前,想明白一些基础知识。
细心的朋友可以看出来,我们插入 Id 时候数据是乱的,插入进去之后,数据就自动帮我通过 Id 进行排序了,这是为什么呢?接着往下看。
我们如果对于 B+ 树有点了解的话就知道 B+ 树是每页 16KB 进行数据储存。在进行数据查询的时候也是一页一页的去查询。
相当于下面的数据。
首先每一页都有很多数据,就像我们平常去写分页的时候我们返回给前端的数据也会有很多属性。
MySQL数据页这个可能比较抽象,我是把他当成平常,分页查询的思想代入进去。
我们可以把一页想成是一个对象。
@Data
public class page {
List data;
// ....省略其余属性
}
我们先看一下,一页数据的图是什么样子,仅仅是进行逻辑思考画的图。
这里的 Data,就相当于 一页中的数据区域。
数据区域但是这里是有限制的,上面我们说到,一页的数据只能是 16Kb,也就是一个 Page 里面的 data 只能16Kb。当数据超过 16Kb,就会新开一个对象相当于在进行创建树的时候增加了判断。
Java 代码思路模拟:
Java模拟MySQL数据页当 Page 对象的大小已经达到16Kb 就算完成这一页。把这一页放到,磁盘中等待使用就行了,到时候进行查询数据的时候会直接返回这一页,里面包含这些数据。
我们回到最初的问题 为什么我们在进行插入的时候明明 Id 是乱的?等到插入到数据的时候,数据就变成有序的了?我们知道,同时这个数据是根据主键进行排序的,InnoDB 的数据储存一定是要依赖主键的,有些人会想,我就是不创建主键,他还能排序吗?
我们在疑问一的基础上,产生出的疑问,不设置主键 Mysql 怎么办?
InnoDB 对聚簇索引处理如下:
很明显,缺少主键的表,InnoDB 会内置一列用于聚簇索引来组织数据。而没有建立主键的话就没法通过主键来进行索引,查询的时候都是全表扫描,小数据量没问题,大数据量就会出现性能问题。
但是,问题真的只是查询影响吗?不是的,对于生成的 ROW_ID,其自增的实现来源于一个全局的序列,而所以有 ROW_ID 的表共享该序列,这也意味着插入的时候生成需要共享一个序列,那么高并发插入的时候为了保持唯一性就避免不了锁的竞争,进而影响性能
我们看完疑问二的解答就知道,即便我们不设置主键。数据也会帮我们去生成一个默认的主键,有点像,类默认生成构造器的思想。
有了主键之后呢?
表中有主键为什么会自动排序,大家都知道了。其实在文章之初就会有很多人明白是为什么,大概脑子里会有答案。
为什么要进行排序?
我们都知道,在进行数据查找的时候,比如几个基础的查找算法的,前提都是,先进行排序。再者 List 和 Map 的一些区别肯定都很熟悉了。排序当然是为了更快,所以无须的 Id 会对插入效率造成影响,也就是为什么很多文章说使用自增 Id 比 UUID 或者雪花算效率高的原因。第一个是 UUID 他们是随机的 每次都要重新排序,甚至可能会因为排序的原因造成页数据的更换。还有就是 UUID 一般都比较长,一页是 16Kb 数据越短。一页的数据就会越多,查询的速度也就比较快。
这里说完为什么排序 还有一个点就是上面的「页目录」
页目录的作用是什么?
页目录的作用是减少范围。
页目录这里的第三层是数据,上面都是目录,可以增加数据的检索效率。
页目录增加数据的检索效率如果没有目录我们需要去直接遍历数据区域,会降低效率。目录能帮我们缩小范围,这里,我们查询 ID = 3。我们可以通过目录知道 1 < 3 < 4,如果在 1 中没有找到对应数据。但是因为 3 < 4 就不会接着往下查询了,直接返回空结果。
当第一页没有的时候去第二页查询,不会直接跳到第二页查询。
提高范围查找效率为了提高效率,当目录数据数量过多时,就会网上延伸一层树,同时可以减少磁盘的 IO 次数。
索引就是一颗树关于所有叶子节点都处于同一深度是如何实现的?这与 B+ 树具体的插入和删除算法有关。简单解释一下插入时的情况,根据插入值的大小,逐步向下直到对应的叶子节点。如果叶子节点关键字个数小于 2t,则直接插入值或者更新卫星数据;如果插入之前叶子节点已经满了,则分裂该叶子节点成两半,并把中间值提上到父节点的关键字中,如果这导致父节点满了的话,则把该父节点分裂,如此递归向上。所以树高是一层层的增加的,叶子节点永远都在同一深度。
基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能
- 项目地址:https://github.com/YunaiV/yudao-cloud
- 视频教程:https://doc.iocoder.cn/video/
感觉写的有点啰嗦了 但是还是有点加深印象的 后续会接着整理一下相关的资料 补充进来
建议收藏
赞赞来一个
会修正
审核编辑 :李倩
全部0条评论
快来发表一下你的评论吧 !