上一篇:
红黑树详解
目录
1、先来了解几个概念
(1)、操作系统磁盘局部性原理:
(2)、这里我们讲一下mysql的int类型字段(考虑数据库索引用int类型):
2、为什么会有B-tree? B-tree的衍生:
3、B-tree介绍
4、B+tree
5、B+Tree,B-Tree 和 二叉树的区别:
内存比磁盘的读写速度要快很多,但内存容量要远小于磁盘,数据,程序的执行要调入内存后才能执行,所以内存和磁盘要经常进行I/O操作;每一次I/O时,不仅仅把当前磁盘地址的数据加载到内存,同时也把相邻数据也加载到内存缓冲区中。
操作系统是分页读取和存储的,每次读取和存取的最小单元为一页,一页的大小与操作系统有关,一般为4k或者8k。这也就意味着读取一页内数据的时候,实际上发生了一次磁盘I/O;
mysql在建表的时候int类型后的长度代表什么? 是该列允许存储值的最大宽度吗? 为什么我设置成int(3), 也一样能存10,100,1000呢?
这里面的3,指示最大显示宽度。显示宽度与存储大小或类型包含的值的范围无关;
int类型, 占用字节数为4byte, 学过计算机原理的同学应该知道, 字节(byte)并非是计算机存储的最小单位, 还有比字节(byte)更小的单位, 也就是位(bit),一个位就代表一个0或1; 8个位组成一个字节; 一般字节用大写B来表示byte, 位用小写b来表示bit.
计算机存储单位的换算:
1B=8b
1KB=1024B
(3)、而在mysql数据中,也存在局部性预读,以InnoDB引擎为例,每一页大小16KB,即16384Byte;
(4)什么是B-tree?
Balanced tree,多路平衡查找树,简称B-tree,而国内很多人喜欢把B-tree译作B-树,其实,这是个非常不好的直译,
很容易让人产生误解。如人们可能会以为B-树是一种树,而B树又是一种一种树。而事实上是,B-tree就是指的B树。特此说明。B-tree是平衡二叉查找树的一种变种树;
我们面对这样一个实际问题:大规模数据存储中,实现索引查询这样一个实际背景下,在数据之外,数据库系统还维护着满足特定查找数据的算法数据结构。这些数据结构以某种方式引用(指向)数据,这样就可以在这些数据结构上实现高级查找算法。这种数据结构就是索引;
索引是为了加速对表中数据行的检索而存创建的一种分散存储的数据结构;
一般来说,索引本身也很大,不可能全部存储在内存中,因此索引往往以索引文件的形式存储的磁盘上。这样的话,索引查找过程中就要产生磁盘I/O消耗,相对于内存存取,I/O存取的消耗要高几个数量级,所以评价一个数据结构作为索引的优劣最重要的指标就是在查找过程中磁盘I/O操作次数的渐进复杂度。换句话说,索引的结构组织要尽量减少查找过程中磁盘I/O的存取次数。
程序运行期间所需要的数据通常比较集中。由于磁盘顺序读取的效率很高(不需要寻道时间,只需很少的旋转时间),因此对于具有局部性的程序来说,预读可以提高I/O效率。
文件系统及数据库系统的设计者利用了磁盘预读原理,将一个节点的大小设为等于一个页(page),每页大小4kb或8kb左右,这样每个节点只需要一次I/O就可以完全载入。为了达到这个目的,在B-Tree每次新建一个节点的同时,直接申请一个页的空间,这样就保证一个节点物理上也存储在一个页里,加之计算机存储分配都是按页对齐的,就实现了一个节点node只需一次I/O。
树的高度决定了I/O的次数,树高度越低,那么I/O性能就越好;
也就是说,因为磁盘的操作费时费资源,如果过于频繁的多次查找势必效率低下。那么如何提高效率,即如何避免磁盘过于频繁的多次查找呢?根据磁盘查找存取的次数往往由树的高度所决定,所以,只要我们通过某种较好的树结构减少树的结构尽量减少树的高度,那么是不是便能有效减少磁盘查找存取的次数呢?那这种有效的树结构是一种怎样的树呢?但是二叉树每个节点只能存一个关键字的数据,无法很好的利用操作系统和磁盘的数据交换特性和磁盘预读能力;而且二叉树高度又太高,每查找一次新的节点,就会有一次I/O操作,而且只有两路,所以用来做索引的话,效率比较低;
这样我们就提出了一个新的查找树结构——多路查找树。根据平衡二叉树的启发,自然就想到平衡多路查找树结构,也就是这篇文章所要阐述的第一个主题B-tree,即B树结构;
如下图就是一颗B-tree,是一颗三路树:
17、35是第一层的关键字节点,有P 1、P 2、P3三路,小于走左边查找,大于走右边查找,位置之间的走中间查找;
一般路的数=关键字数+1,如果索引关键字节点(每个节点能存储4kb数据)的索引字段名称越短的话,每个节点存储的关键字数越多,路数也会变多,那么就导致了树的层级变低,每次I/O能够查找到数据的机会就越大,这样整体上就减少了I/O的搜寻次数,提高了效率;
(1)、许多数据库系统都一般使用B树或者B树的变形结构B+树;
mysql选择了下图中的B+Tree,有以下特点:
a、B+Tree保存数据搜寻采用了左闭合区间,<=查找;
(
(a)、因为数据都存储在叶子节点,即使命中等于了,还是需要向下层找到叶子节点的数据伪代码:
if(x<=node){
//继续向下层查找,=也继续向下查找,因为要到叶子节点才能返回数据,
//中间的节点没有存储数据
}
(b)、还有一个原因:如果没有指定建立索引,mysql会在主键上建立默认索引,有的主键ID是采用自增规则,
所以它会 认为常见的数据都会存在B+tree的右边,左边是不常见的;
);
b、B+Tree非叶子节点,不保存数据相关信息,只保存关键字和子节点相关信息;
c、B+Tree关键字对应的数据保存在叶子节点中;
d、B+Tree的叶子节点是顺序排列的,并且相邻节点具有顺序引用的关系;
B+tree 入下图:
(2)、那么回到B+tree,假设用的是InnoDB引擎,一个节点(一页)能存储16KB的数据,16KB= 16384B,16384B/4B = 4096,
所以当索引存储int类型(占用字节数为4byte)的字段的时候,理论上一个节点(一页)就能存储4096个关键字,但是实际上还有一些其他数据的存储,实际上能存储的关键字个数少于4096,假如能存储约3500个左右关键字,这样每一次I/O操作,就能查找到3500个关键字数据;
(3)、B+tree的插入过程中,也有可能导致树不平衡,为了保持平衡,进行树的旋转,会对性能有影响;所以一些经常有删除、修改操作数据的字段,不适合建立索引;
(4)、B+tree和B-tree对比的优势在哪里?
a、B+tree扫库、表能力更强(B+tree因为只有子节点存储了数据,只需要去扫描子节点,并且子节点有指向关系,所以更快)。
b、B+tree的磁盘读写能力更强(因为非叶子节点,没有存储数据,节省的这部分空间,能用来保存更多的关键字个数,所以降低了树的高度,减少I/O次数)。
c、B+tree的排序能力更强(要是能看懂这个应该不用再问)。
d、B+tree的查询效率更加稳定(仁者见仁、智者见智)(一定会查找到最下层的叶子节点返回数据,不管在前面的节点中是否命中)。
(5)、mysql不同的存储引擎:
MyISAM & InnoDB 都使用B+Tree索引结构。但是底层索引存储不同,MyISAM 采用非聚簇索引,而InnoDB采用聚簇索引。
聚簇索引: 索引 和 数据文件为同一个文件。就是指主索引文件和数据文件为同一份文件,聚簇索引主要用在Innodb存储引擎中。在该索引实现方式中B+Tree的叶子节点上的data就是数据本身;代表数据的物理存储顺序;
非聚簇索引: 索引 和 数据文件分开的索引。指B+Tree的叶子节点上的data,并不是数据本身,而是数据存放的地址。索引顺序与数据物理排列顺序无关;
MyISAM引擎:查询销量较高;
InnoDB最大的特点就是支持行锁和事务;大多数互联网公司用的InnoDB引擎:
关于这两种索引区别,可以读一下这篇文章:https://blog.csdn.net/qq_27607965/article/details/79925288
二叉树是从上向下插入的,但是B+Tree,B-Tree是在插入数据的时候,自下向上分裂,如下图
其他参考链接:https://www.jianshu.com/p/f635a6a94254
https://blog.csdn.net/v_JULY_v/article/details/6530142
https://www.cnblogs.com/wuzhenzhao/p/10341114.html