数据结构与算法-Btree&B+Tree

       一:引入

         作为一个IT从业者大家对数据库肯定是都知道的,大家应该知道在数据库中有个索引,在一张表中用了索引与不用索引那查找效率简直就是天壤之别,但是大家有没思考过,你经常用的索引是什么样的数据结构呢?它为什么又能这么高效的查找呢?究竟使用了什么样的算法呢?

        select * from user where  user_id = 100

        select * from user where  user_id  > 10

        select * from user where  user_id = 100  and name = “ykw”

 如果是你你该如何利用我们已经学过的知识来设计上面这个sql的索引结构呢?

        二:改造二叉查找树

        改造二叉搜索树: 大家看我改造后的二叉搜索树,

        执行 select * from table where id = 10

        执行 select * from table where id > 12

        select * from table where id > 12 and  id < 20

二叉查找树

        效果:  能解决我们上面所有的sql语句; 效率 logn 2^32=21亿;

        IO:指的是从磁盘读取数据。32层就要读取32次。CPU,内存,IO;

        IO从磁盘读一次会读多少数据?计算机组成原理。Page的。页,4KB。

        Int占多少空间?4B

        通过以上可知我们能够把sql语句的功能都能实现,而且效率也很高,那是不是这种结构 就可以作为mysql的索引了呢? 大家想想,右边这个结构我们是存在哪里的?有什么问题?怎么解决?

        问题1:搜索效率:32次

        问题2:查询次数:

        问题3:磁盘IO:解决这个问题;引出Btree

二叉查找树的改进:B+Tree

       

        所以为了让我们磁盘的存储效率达到最高利用率,就引入了B+Tree,B+树只在叶子节点中存储键值,非叶子节点中只存储键值的索引。B+树的叶子节点通过指针进行连接,使得数据的遍历更加高效。也可以是M阶B+Tree。

        引出经典面试题:为什么mysql用B+tree而不用Btree?

                1.Btree的每个结点存储的不仅有索引,还会存入数据,同时mysql规定一个磁盘页存的大小为16k,也就是一个结点存的大小为16k,假如每个索引+数据的大小为1k,则一个结点只能存入16个索引,那么如果单表存入2千万条的话,Btree的高度就估计是16^n=2千万,(n:就是高度),高度越高意味的IO次数越多,就越耗时。而B+tree不用,B+tree是非叶子结点值存入索引,因此可以保证非叶子结点存入多个索引,那么高度就越底,io次数耗时越少更高效 。(所以当一个结点放的索引越多,那么相同的数据量下,树的高度就越小)

                2.B+tree的叶子结点不仅存入索引和data,还有相互的指针,可以提高区间访问性能

三:M阶B+Tree

     B+Tree的性质:  

        M阶的B+Tree:叉树

        (1)每个节点最多有m个子节点

        (2)除根节点外,每个节点至少有m/2个子节点,注意如果结果除不尽,就向上取整,比如5/2=3。 3/2=ceil(1.5)=2

        (3)根节点要么是空,要么是独根,否则至少有2个子节点

        (4)有k个子节点的节点必有k个关键码:就是 有m个数据就有m个叉叉;

        (5)叶节点的高度一致:这个的 好处是什么? 满树?连续?(为了保证我的将来查询的次数是相同的,不会因为变量的改变而改变。)

B+tree数据结构

四:mysql下的B+tree

     2.1  B+Tree在Mysql中的分析

                1.阶数:通过上面的分析我们知道这个阶数很重要直接决定了B+Tree的查找效率以及性能,那么在Mysql中我们如何设定这阶数呢?

                 通过mysql的页大小决定,一般是16k。那么一个主键类型为bigint的字段建索引大约的消耗空间是多少呢?

        Int:8字节,指针一个也算4字节。

        一页的节点:16kb/ (8b+8b)=1k 键值+指针 我们刚举例的3阶B+Tree你们计算下可以存多少索引值? 1024*1024*1024=多少?

可想而知如果在理想情况下 我们的mysql查询是不是很高效,一般最多也就4阶左右的B+Tree。

        

     2.2、具体计算方法

        2.1、根节点计算

首先我们只看根节点,假设我们设置的数据类型是bigint,大小为8b,在数据本身还有一小块空间,用来存储下一层索引数据页的地址,大小为6kb。所以我们可以计算出来一个数据为(8b+6b=14b)的空间(以bigint为例)。

我们刚才说到一个数据页的大小是16KB,也就是(16*1024)b,那么根节点是可以存储(16*1024/(8+6))个数据的,结果大概是1170个数据。

        2.2、其余层节点计算

第二层的数据量是1170*1170=1368900,问题在于第三层,因为innodb的叶子节点,是直接包含整条mysql数据的,如果字段非常多的话数据所占空间是不小的,我们这里以1kb计算,所以在第三层,每个节点为16kb,那么每个节点是可以放16个数据的,所以最终mysql可以存储的总数据为1170*1170*16=21902400(千万级条)。

        3、总结

综上,我们通过计算得出,MySQL一张表的最大数据量为21902400(千万级条)。实际上,一般在MySQL的一张表中超过了千万数据,我们就会考虑进行分表操作了。

  2.3 根据我们所学的数据结构知识,我们应该如何正确的建立索引:

        1.索引不能太多,因为B+tree的插入和删除是要维护的,太多的索引会导致插入变慢。         2.建了索引的字段不能使用like ‘%%’否则是失效的

        3.建索引的字段类型不能太大,字段越小阶数就越大,效率就越高,int 和 bigint,varchar(10),varchar(100),text,lontext;B+Tree。全文索引

        4.建索引的字段值不能太多一样的,数学里面有个叫什么散列多一些(离散),比如我们把性别建索引会出现啥情况?左边都是一样的值 过滤不了一半。User sex单独建索引 0 1         5.联合索引的最左匹配原则。当创建联合索引时,索引由多个列组成,例如(A, B, C),其中A是最左边的列,B是中间的列,C是最右边的列。在使用该联合索引进行查询时,MySQL会优先使用索引的最左边的列进行匹配,然后再根据需要使用中间列和最右边的列进行进一步的筛选。 这意味着,如果查询只涉及到了联合索引的最左边的列,那么索引将可以被完全利用,进行高效的查询。但是,如果查询中包含的列不是索引的最左边的列,那么索引的效果将会减弱,甚至可能不被使用。 举个例子,如果有一个联合索引 (A, B, C),而查询条件只包含了列A,那么索引将会被完全利用。但如果查询条件只包含了列B或C,那么索引的效果将会减弱,可能需要进行全表扫描。

        例子:假如下图的话,联合索引(name,age,aderss)

        sql:select * from user where age = 30  查的话那么就不会走索引,因为B+tree是按照排好序的原理,按照从左到右的索引字段已经排好序,跳过name的话就不是排好序,否则就是全表扫描。

最左匹配原则例图

        6.NOT IN 是不会走索引的 not in (1,2,3) In的值太多 mysql会报错的。上线的

五:小结

        二叉查找树,红黑树,B-Tree,B+Tree 的区别:

           二叉查找树:二叉搜索树,优点查找快,但是在某些情况下会退化成链表,它是所有 高效查找树的基础,如果不懂这个 其他的也学不懂。根本性的东西,最好能自己手写出来。

           红黑树:内存查找高效树,不适合大数据量 也不适合磁盘存储的。具体的分析就是IO浪费以及读取资源浪费,还有就是树的深度会很大。适合一些底层系统做内存运算

           B-Tree:所有的节点都会存数据,可以认为是B+Tree过度。只需要知道BTree就可以

           B+Tree:最适合大数据的磁盘索引,经典的MySql,所有的数据都存在叶子节点。其他都是索引,增加了系统的稳定性以及遍历以及查找效率 不同:关键字和Key值。数据存储的地方,双向链表。

           M阶:这个由磁盘的页面大小决定,磁盘快和页内存都是4KB。我们的节点数也就是我们的M值 应该要尽可能的跟他一样。1 0.75的原则HashMap。这样的好处就是为了我们一次刚好能全部拿出一个节点里面存的所有的数据。

猜你喜欢

转载自blog.csdn.net/qq_67801847/article/details/132792847