Java实践6索引之B树B+数、持久化、详解

Java实践6索引之B树B+数、持久化、详解

  索引是我们开发、和面试中需要理解的重要的数据结构,常用的B树、hash索引、位图索引。大家是不是经常和我一样有很多疑问?关系数据库为什么用B树,它有特点是什么,为什么看过而很多文章,什么M节点、叶节点,有点晕?背完概念之后,还是容易忘记?还有没有其他索引?hash索引它的特点是什么?其实理解他们之后,就不用看八股文了,推导一下那些问题就很容易理解了,下面和大家分享一下,我对他们的理解。

B树、B+树索引

  B树很重要的一种数据结构, 它是一种自平衡的树。被应用在方方面面,比如数据库,比如文件系统等等很多地方都借鉴了B树的思路,理解他的工作过程,对我们今后的工作有很大的帮助。比如我们需要实现排序查询,而且内存不够,那么B树会是很好的选择。现在我们来看看B树,是如何工作的,很多文章画了注记图。比如这个
在这里插入图片描述
又或者是这个?
在这里插入图片描述他是如何提高查询效率的?如何减少IO的?mysql中数据页是怎么回事?数据页为什么默认是16K?为什么说B树能落盘呢,占内存吗?等等问题。下面大家跟着我的思路来,看一下相信很快就能够明白了。
  首先大家看一下下图简单的树图,大家可以尝试理解一下,实际这样是没用的,我们用代码实现的话是无法提高查询效率的。
在这里插入图片描述
  那么我们如何做,提高效率并理解B树呢?可以大家跟着我的思路一点点的去优化他,相信大家就明白了。

1、优化版带地址位的树

  根据上面简单的树,在每个数据前后增加地址位,来指向比它大的和比他小的数据的地址。
  类似这样的树。那它是如何工作,磁盘又是怎么存储的呢?
在这里插入图片描述
下面来模拟一下带地址位的插入流程分别插入4、2、1、6。

1)插入4时,创建第一个块,P=0,存放3个数据。
(第二位存放数据,第一位存放比数据小的 数据地址偏移量,第三位存放比数据大的,数据地址偏移量)
把4放入第一个块,设置P=P+3
在这里插入图片描述2)继续插入2,,目前P=3
–从头开始搜索,第一个块已经有值,拿出第一个块,
–判断2<4取4前面的指向目前为null。
–根据P创建第二个块,把2插入第二个块,
–把4的前一位置指向2的偏移地址。最后P=6
在这里插入图片描述3)继续插入1,
-从头开始搜索,第一个块已经有值,拿出第一个块,
-判断1(插入值)<4(第一个块),取4前面的指向,目前已经指向第二块。
-取出第二个块,判断1(插入值)<2(第二个块值),取2前面的指向,目前为null。
-根据P创建第三个块,把1插入第三个块,
–把2的前一位置指向1的偏移地址。最后P=9
在这里插入图片描述3)继续插入6,
-从头开始搜索,第一个块已经有值,拿出第一个块,
-判断6(插入值)>4(第一块),取4后面的指向,目前为null。
-根据P创建第四个块,把6插入第四个块,
-把4(第一块)的后一位置指向6的偏移地址。最后P=12

下面为最后的磁盘存储图:
在这里插入图片描述下面是方便理解的树型图:

在这里插入图片描述
其实他们的主流程都一样。都是先从第一块开始搜索,通过比较块的数据和插入的数据,来设置块的前后指向。然后根据P来确定,插入的数据,放入磁盘文件的什么位置。
  大家可以发现上面设计的树数据结构是有问题的。虽然这样可以存放到磁盘,但是每次操作时(增删改查),每次数据都是1小块操作的。这样也是比较耗费IO的。假如一个小块是3个long,那么每次我们IO要操作24 byte。
可参考 文件IO实践 每次读的太小程序会很慢。

2、优化版增加页、阶的概念

  基于刚才的问题,我们把多个小块,放到一个大的块中,把这个大的块定义为页。那么这个页(大的块)中有多少个小块 ,再+1,这个定义为阶。
  例如:2、4、6三个小块,都放到一个大块中,这个大块叫页,块中最多有3个小块,那么的阶为4.
在这里插入图片描述
增加页之后,那么我们可以面向页来操作,每次读取操作一页的数据,然后在内存中可以使用二分查找来排序 查找数据,没有需要的则取下一页。

小知识 什么是内存/磁盘对齐?

首先磁盘的存储也是一个小块一个小块排列的。
  看下图:假设设磁盘/内存,一个小存储块能放2个int数据。我们放入20和10两个数据。如果不做内存对齐, cpu一次寻址只会取一个存储单元数据,那么当插入/查询“20 10”时,我们需要2次执行,才能得到结果。如果做了对齐则1次就可以查到结果了。
在这里插入图片描述
所以我们在操作时要做内存对齐,提高操作效率。大家理解意思即可,实际的磁盘存储一块好像是4KB。

  大家可以看到增加了页和阶的概念后,还是有问题。比如2和4之间使用1个位置存放指针即可。

在这里插入图片描述再比如,刚才的设计数据倾斜了,怎么办?

3、B树(数据分裂 解决数据倾斜问题)

  读完1和2的内容,大家是否有一点感觉了呢?那么我们继续说最终基于1和2的思路如何解决数据倾斜的呢?
   增加分裂操作逻辑
  --如果该页上的数值未满(判断阶),则将新数值插入到该页中,注意页中数据的顺序。 --如果该节点上的数值已满,则需要将该页分裂成两个页:从该页中的数值和新数值选出中位数。
  ----小于中位数的数值放到左边页中,大于中位数的数值放到右边页中,中位数做为分隔值。 ----分隔值被插入到父页中,注意父页中也有可能会分裂。以此类推。
下面用图来演示一下一个3阶的数据索引插入过程。左侧为磁盘操作过程,右侧为方便理解的抽象过程。

在这里插入图片描述在这里插入图片描述在这里插入图片描述  大家一定要深入理解上面的过程,了解磁盘的变动,新建页、分裂的过程等等。了解后我们可以知道,B树是非常节约内存的,内存只保留根节点即可,每次查询只查询一页的数据。2000w的数据。一次等值查询, 3次IO即可找到数据。
  计算过程:假设long做索引占8位+8位存放地址,那么16k一页约可存放16k/24byte≈1000个(主键+索引地址指针+数据地址指针),那么高度为3的话, 1000100016,大约能存储约2000w条数据。

4、B+树

  通过理解上面的B树,那么B+树就很容易理解了,在B树的基础上,每个页数据增加增加一个位置,存放最底层页指针,把底层的页连一起即可。
在这里插入图片描述
注意B加数在插入,阶满需要分裂时,中位数也要放入到新的页中。

5、B+树和B树的区别

  理解了B树和B+树,那么从图中可以看到。
他们插入时,都需要从根页开始查找。一页一页的取,如果此页没有,则通过二分搜索的方式,找到应该查找的下一个页的位置。

1、范围查询区别

  B+树,在实现上会更复杂。支持范围查询,如果需要范围搜索例如a<=3后:先从根开始搜索,到最底层3的所属页,然后通过链的方式查找到1。 需要4次IO。
在这里插入图片描述
  B树,则范围查询时,如果搜索a<=3时,–先从根开始找到底层3,–然后再返回到根查熏到底层2,-然后再返回2,查找1。需要5次IO。

在这里插入图片描述

2、普通等值查询

对于普通的查询
  B树在页中的索引数据,没有重复的,所以每一页中索引数据都要跟随着,真实数据的地址偏移量。如果幸运的话根节点就能找到数据。如果不幸运的话则需要查找到底层。
   B+树,在页中只有最底层才存放,索引数据 对应真实数据的地址偏移量,非最底层无需存放,所以可以多存一些索引。 由于B+树一次IO可以取到更多的索引,所以比B树也会快一点。

6、页为什么是16k

  为什么mysql 页要设置16k呢?是4的倍数是因为要做对齐,为什么16K这个刚才计算过,大约能存储2000w的数据。这个数值我认为比较中庸,兼顾了数据量也兼顾了效率,数据量不很大,但也很小,我认为是这个原因。把页调大,我觉着可以优先考虑分库分表来优化。把页调小,IO次数会增加。所以目前来看16K是比较合适的。

总结:

  1)关于一些概念,比如页、阶。其实他们也是比较简单的,就是利用分治的思想,分块去处理数据。内存只保留1个根节点的偏移地址即可。耗费很小的内存。对磁盘友好,查询效率较快。
  2) 范围查询和等值查询,B+树都会快一些,实现也会更复杂一些。如果是不等值查询B树则会失效。无法使用二分查找来确定数据位置了。
   3)页为什么是16K,理解后,我们可以根据业务去设置它的大小,存放更多的索引。
  4)内存对齐这个就很简单了,有可能我们在数据库中用不到,但我们可以理解他的原理,在我们的日常开发中,也借鉴这种方式做对齐,来提升我们的代码运行效率。
  5)其实还有很多细节也都没讲到,比如根节点的变化与保存,我们插入时实际上是索引+数据一起插入,由于比较复杂,目前水平优先,不好表达,这些就需要大家后面思考一下了。
  其实理解B树、B+树的在磁盘中的操作、分裂过程后。再看一那些概念,和一些问题,就很简单了。有空大家其实可以实现下代码,这个还是挺复杂的,就算不实现那么我们也可以思考一下实现,这有助于帮助我们更好的去理解。

  好了这篇分享完了,希望对大家会有帮助,文章中有哪些错误,或者理解的不对,欢迎大家多多和我交流、批评和指正。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值