b树与b 树的区别 mysql_浅析——B树,B+树,B*树以及分析MySQL的两种引擎

接触到了数据结构当中的B树,B+树,B*树,我以为应该写一篇博客记录下,毕竟是第一次接触的,只有写了博客之后,感受对这个的印象才会更加深入。

前言:

为何要有B树?

学习任何一个东西咱们都要知道为何要有它,B树也同样,既然存储数据,咱们为何不用红黑树呢?php

这个要从几个方面来讲了,

计算机有一个局部性原理,就是说,当一个数据被用到时,其附近的数据也一般会立刻被使用。

因此当你用红黑树的时候,你一次只能获得一个键值的信息,而用B树,能够获得最多M-1个键值的信息。这样来讲B树固然更好了。

另一方面,一样的数据,红黑树的阶数更大,B树更短,这样查找的时候固然B树更具备优点了,效率也就越高。web

一.B树

首先咱们来谈一谈关于B树的问题,算法

对于B树,咱们首先要知道它的应用,B树大量应用在数据库和文件系统当中。数据库

B树是对二叉查找树的改进。它的设计思想是,将相关数据尽可能集中在一块儿,以便一次读取多个数据,减小硬盘操做次数。数组

B树为系统最优化大块数据的读和写操做。B树算法减小定位记录时所经历的中间过程,从而加快存取速度。广泛运用在数据库和文件系统。数据结构

假定一个节点能够容纳100个值,那么3层的B树能够容纳100万个数据,若是换成二叉查找树,则须要20层!假定操做系统一次读取一个节点,而且根节点保留在内存中,那么B树在100万个数据中查找目标值,只须要读取两次硬盘。svg

B 树能够看做是对2-3查找树的一种扩展,即他容许每一个节点有M-1个子节点。性能

B树的结构要求:

1)根节点至少有两个子节点

2)每一个节点有M-1个key,而且以升序排列

3)位于M-1和M key的子节点的值位于M-1 和M key对应的Value之间

4)其它节点至少有M/2个子节点

5)全部叶子节点都在同一层

a40960dea196970bcdb17283b5048afc.png

根据B树的特色,咱们首先能够写出B树的总体的结构。学习

1.B树结构

B树的结构咱们定义须要参考规则,咱们首先是须要给出保存键值的一个数组,这个数组的大小取决与咱们定义的M,而后咱们根据规则,能够获得一个保存M+1个子的一个数组,而后固然为了方便访问,parent指针,而后要有一个记录每一个节点中键值个数的一个size。

因此定义以下:

template

struct BTreeNode

{

K _keys[M]; //用来保存键值。

BTreeNode* _sub[M + 1]; //用来保存子。

BTreeNode* _parent;

size_t _size;

BTreeNode()

:_parent(NULL)

, _size(0)

{

int i = 0;

for ( i = 0; i < M; i++)

{

_keys[i] = K();

_sub[i] = K();

}

_sub[i] = K();

}

};

2.B树的查找

对于AVL,BST,红黑树,B树这些高级的数据结构而言,查找算法是很是重要的。咱们首先肯定返回值,对于这种关于key和key-value的数据结构,参考map和set,咱们让它返回一个pair的一个结构体。

pair结构体的定义在std中是优化

template

struct pair

{

K key;

V value;

}

咱们只须要让这个里面的value变为bool值,value返回之后说明的是存不存就能够了。

接下来的思路就是从根节点进行和这个节点当中的每个key比较,若是=那么就返回找到了,若是小于,那么就到这个节点左面的子节点中找,若是大了,就继续向后面的键值进行查找。若是相等那么就返回。

示例代码:

pair Find(const K &key)

{

Node* cur = _root;

Node* parent = NULL;

while (cur)

{

size_t i = 0;

while (i < cur->_size)

{

//若是小于当前,向后

if (cur->_keys[i] < key)

{

i++;

}

//若是大于,

else if (cur->_keys[i]>key)

{

cur = cur->_sub[i];

parent = cur;

break;

}

//相等,返回这个节点

else

{

return pair(NULL, -1);

}

}

if (key > cur->_sub[i + 1])

{

cur = cur->_sub[i];

}

//为了防止出现我返回空指针操做,若是是空指针,那么就返回父亲

if (cur != NULL && i == cur->_size)

{

parent = cur;

cur = cur->_sub[i];

}

}

return pair(parent, 1);

}

3.B树的插入

d8be63a767a0186f31184b3de1e71cb1.png

示例代码:

bool Insert(const K &key)

{

//首先来考虑空树的状况

if (_root == NULL)

{

//给这个节点中添加key,而且让size++。

_root = new Node;

_root->_keys[0] = key;

_root->_size++;

return true;

}

//使用通用的key-value结构体来保存找到的key所在的节点。

pair ret=Find(key);

//在这里来看这个节点是否存在,存在就直接return false。

if (ret.second == -1)

{

return false;

}

Node* cur = ret.first;

K newKey = key;

Node *sub = NULL;

//此时表示考虑插入。

while (1)

{

//向cur里面进行插入,若是没满插入,满了就进行分裂。

InsetKey(cur, newKey, sub);

//小于M,这样就能够直接插入

if (cur->_size < M)

{

return true;

}

//若是==M,那么就应该进行分裂

//首先找到中间的节点

size_t mid = cur->_size / 2;

//建立一个节点,用来保存中间节点右边全部的节点和子节点。

Node * tmp = new Node;

size_t j = 0;

//进行移动sub以及全部的子接点。

for (size_t i = mid + 1; i < cur->_size; i++)

{

tmp->_keys[j] = cur->_keys[i];

cur->_keys[i] = K();

cur->_size--;

tmp->_size++;

j++;

}

//移动子串

for (j = 0; j < tmp->_size + 1; j++)

{

tmp->_sub[j] = cur->_sub[mid + 1 + j];

if (tmp->_sub[j])

{

tmp->_sub[j]->_parent = tmp;

}

cur->_sub[mid + 1 + j] = NULL;

}

//进行其余的移动

//分裂的条件就是要么分裂根,要么就是分裂子节点,要么就是所在节点的节点数小于M。

//考虑根分裂,分裂的时候建立节点,而后把中间节点上拉,记得要更改最后的parent

if (cur->_parent == NULL)

{

_root = new Node();

_root->_keys[0] = cur->_keys[mid];

cur->_keys[mid] = K();

cur->_size--;

_root->_size++;

_root->_sub[0] = cur;

cur->_parent = _root;

_root->_sub[1] = tmp;

tmp->_parent = _root;

return true;

}

//分裂若是不是根节点,那么就把mid节点插入到上一层节点中,而后看上一层节点是否要分裂。注意修改cur和sub

else

{

newKey = cur->_keys[mid];

cur->_keys[mid] = K();

cur->_size--;

cur = cur->_parent;

sub = tmp;

sub->_parent = cur;

}

}

}

void InsetKey(Node* cur, const K &key, Node* sub)

{

int i = cur->_size - 1;

while (i>=0)

{

//进行插入

if (key > cur->_keys[i])

{

break;

}

//进行移动

else

{

cur->_keys[i + 1] = cur->_keys[i];

cur->_sub[i + 2] = cur->_sub[i + 1];

}

i--;

}

//进行插入

cur->_keys[i + 1] = key;

//插入子

cur->_sub[i + 2] = sub;

//若是没满,只须要对size++;

if (cur->_size < M)

{

cur->_size++;

}

}

二.B+树

接下来介绍B树的升级版本,

B+树

B+树是B-树的变体,也是一种多路搜索树:

1.其定义基本与B-树同,除了:

2.非叶子结点的子树指针与关键字个数相同;

3.非叶子结点的子树指针P[i],指向关键字值属于[K[i], K[i+1])的子树(B-树是开区间);

5.为全部叶子结点增长一个链指针;

6.全部关键字都在叶子结点出现;

86e67811770f85432360dbc2c4c98112.png

B+树相比于B树可以更加方便的遍历。

B+树简单的说就是变成了一个索引同样的东西。 B+的搜索与B-树也基本相同,区别是B+树只有达到叶子结点才命中(B-树能够在非叶子结点命中),B+树的性能至关因而给叶子节点作一次二分查找。

B+树只有叶子节点存的是Key-value,非叶子节点只须要存储key就行了。

B+树的查找算法:当B+树进行查找的时候,你首先必定须要记住,就是B+树的非叶子节点中并不储存节点,只存一个键值方便后续的操做,因此非叶子节点就是索引部分,全部的叶子节点是在同一层上,包含了所有的关键值和对应数据所在的地址指针。这样其实,进行 B+树的查找的时候,只须要在叶子节点中进行查找就能够了。

B+树的插入算法与B树的大体思想也是同样的,只不过在这里的上拉就是只把键值上拉。

三.B*树

接下来要说明的就是B*树,B*树是对B+树进行的又一次的升级。在B+树的非根和非叶子结点再增长指向兄弟的指针;

8be4bf2a937c242255387a24c2dd9c5a.png

在B+树基础上,为非叶子结点也增长链表指针,将结点的最低利用率从1/2提升到2/3;

在这好比说当你进行插入节点的时候,它首先是放到兄弟节点里面。若是兄弟节点满了的话,进行分裂的时候从兄弟节点和这个节点各取出1/3,放入新建的节点当中,这样也就实现了空间利用率从1/2到1/3。

四.关于B树和B+树相关应用拓展

其实B树B+树最须要关注的是它们的应用,B树和B+树常常被用于数据库中,做为MySQL数据库索引。索引(Index)是帮助MySQL高效获取数据的数据结构。

为了查询更加高效,因此采用B树做为数据库的索引。

在MySQL中,索引属于存储引擎级别的概念,不一样 存储引擎对索引的实现方式是不一样的,咱们接下来讨论两个引擎:MyISAM和InnoDB这两种引擎。

1.MyISAM

4d7cf170028180568960a0d6483e4501.png

59fb2635cbf1617d66709444ff545157.png

MyISAM中有两种索引,分别是主索引和辅助索引,在这里面的主索引使用具备惟一性的键值进行建立,而辅助索引中键值能够是相同的。MyISAM分别会存一个索引文件和数据文件。它的主索引是非汇集索引。当咱们查询的时候咱们找到叶子节点中保存的地址,而后经过地址咱们找到所对应的信息。

2.InnoDB

5387fe8816f286ab80577aa6d0bbe2ce.png

f61006dc980ae7185170f7e2d4183a83.png

InnoDB索引和MyISAM最大的区别是它只有一个数据文件,在InnoDB中,表数据文件自己就是按B+Tree组织的一个索引结构,这棵树的叶节点数据域保存了完整的数据记录。因此咱们又把它的主索引叫作汇集索引。而它的辅助索引和MyISAM也会有所不一样,它的辅助索引都是将主键做为数据域。因此,这样当咱们查找的时候经过辅助索引要先找到主键,而后经过主索引再找到对于的主键,获得信息。

这就是MySQL的两种引擎

这两种引擎那个好呢?

从历史上来讲MyISAM历史更加久远,因此InnoDB性能也就更好了,在这咱们须要考虑当咱们修改数据库中的表的时候,数据库发生了变化,那么他们的主键的地址也就发生了变化,这样你的MyISAM的主索引和辅助索引就须要进行从新创建索引。而InnoDB只须要改变主索引,由于它的辅助索引是存主键的。因此这样考虑InnoDB更加高效。

另外,咱们也就很容易明白为何不建议使用过长的字段做为主键,由于全部辅助索引都引用主索引,过长的主索引会令辅助索引变得过大。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值