B-Tree就是咱们常说的B树,必定不要读成B减树,不然就很丢人了。B树这种数据结构经常用于实现数据库索引,由于它的查找效率比较高。数据库
磁盘读取依靠的是机械运动,分为寻道时间、旋转延迟、传输时间三个部分,这三个部分耗时相加就是一次磁盘IO的时间,大概9ms左右。这个成本是访问内存的十万倍左右;正是因为磁盘IO是很是昂贵的操做,因此计算机操做系统对此作了优化:预读;每一次IO时,不只仅把当前磁盘地址的数据加载到内存,同时也把相邻数据也加载到内存缓冲区中。由于局部预读原理说明:当访问一个地址数据的时候,与其相邻的数据很快也会被访问到。每次磁盘IO读取的数据咱们称之为一页(page)。一页的大小与操做系统有关,通常为4k或者8k。这也就意味着读取一页内数据的时候,实际上发生了一次磁盘IO。数据结构
咱们知道二叉查找树查询的时间复杂度是O(logN),查找速度最快和比较次数最少,既然性能已经如此优秀,但为何实现索引是使用B-Tree而不是二叉查找树,关键因素是磁盘IO的次数。性能
数据库索引是存储在磁盘上,当表中的数据量比较大时,索引的大小也跟着增加,达到几个G甚至更多。当咱们利用索引进行查询的时候,不可能把索引所有加载到内存中,只能逐一加载每一个磁盘页,这里的磁盘页就对应索引树的节点。优化
咱们先来看二叉树查找时磁盘IO的次:定义一个树高为4的二叉树,查找值为10:spa
第一次磁盘IO:操作系统
第二次磁盘IO3d
第三次磁盘IO:blog
第四次磁盘IO:索引
从二叉树的查找过程了来看,树的高度和磁盘IO的次数都是4,因此最坏的状况下磁盘IO的次数由树的高度来决定。内存
从前面分析状况来看,减小磁盘IO的次数就必需要压缩树的高度,让瘦高的树尽可能变成矮胖的树,因此B-Tree就在这样伟大的时代背景下诞生了。
m阶B-Tree知足如下条件:
一、每一个节点最多拥有m个子树
二、根节点至少有2个子树
三、分支节点至少拥有m/2颗子树(除根节点和叶子节点外都是分支节点)
四、全部叶子节点都在同一层、每一个节点最多能够有m-1个key,而且以升序排列
以下有一个3阶的B树,观察查找元素21的过程:
第一次磁盘IO:
第二次磁盘IO:
这里有一次内存比对:分别跟3与12比对
第三次磁盘IO:
这里有一次内存比对,分别跟14与21比对
从查找过程当中发现,B树的比对次数和磁盘IO的次数与二叉树相差不了多少,因此这样看来并无什么优点。
可是仔细一看会发现,比对是在内存中完成中,不涉及到磁盘IO,耗时能够忽略不计。另外B树种一个节点中能够存放不少的key(个数由树阶决定)。
相同数量的key在B树中生成的节点要远远少于二叉树中的节点,相差的节点数量就等同于磁盘IO的次数。这样到达必定数量后,性能的差别就显现出来了。
在刚才的基础上新增元素4,它应该在3与9之间:
删除元素9:
插入或者删除元素都会致使节点发生裂变反应,有时候会很是麻烦,但正由于如此才让B树可以始终保持多路平衡,这也是B树自身的一个优点:自平衡;B树主要应用于文件系统以及部分数据库索引,如MongoDB,大部分关系型数据库索引则是使用B+树实现。