B-Tree和B+Tree

本文来自 Hubery_James 的CSDN 博客 ,全文地址请点击:原文地址-干货满满

B+树索引是B+树在数据库中的一种实现,是最常见也是数据库中使用最为频繁的一种索引。B+树中的B代表平衡(balance),而不是二叉(binary),因为B+树是从最早的平衡二叉树演化而来的。

二、平衡多路查找树(B-Tree)

 
B-Tree是为磁盘等外存储设备设计的一种平衡查找树。

系统从磁盘读取数据到内存时是以磁盘块(block)为基本单位的,位于同一个磁盘块中的数据会被一次性读取出来,而不是需要什么取什么。

InnoDB存储引擎中有页(Page)的概念,页是其磁盘管理的最小单位。InnoDB存储引擎中默认每个页的大小为16KB,可通过参数innodb_page_size将页的大小设置为4K、8K、16K,
在MySQL中可通过如下命令查看页的大小:
mysql> show variables like 'innodb_page_size';

系统一个磁盘块的存储空间往往没有这么大,因此InnoDB每次申请磁盘空间时都会是若干地址连续磁盘块来达到页的大小16KB。InnoDB在把磁盘数据读入到磁盘时会以页为基本单位,在查询数据时如果一个页中的每条数据都能有助于定位数据记录的位置,这将会减少磁盘I/O次数,提高查询效率。B-Tree结构的数据可以让系统高效的找到数据所在的磁盘块。为了描述B-Tree,首先定义一条记录为一个二元组[key, data] ,key为记录的键值,对应表中的主键值,data为一行记录中除主键外的数据。对于不同的记录,key值互不相同

  • 一棵m阶的B-Tree有如下特性 :
     
    1.每个节点最多有m个孩子。 
     
    2.除了根节点和叶子节点外,其它每个节点至少有Ceil(m/2)个孩子。 
     
    3.若根节点不是叶子节点,则至少有2个孩子 
     
    4.所有叶子节点都在同一层,且不包含其它关键字信息 
     
    5.每个非终端节点包含n个关键字信息(P0,P1,…Pn, k1,…kn) 
     
    6.关键字的个数n满足:ceil(m/2)-1 <= n <= m-1 
     
    7.ki(i=1,…n)为关键字,且关键字升序排序。
     
    8.Pi(i=1,…n)为指向子树根节点的指针。P(i-1)指向的子树的所有节点关键字均小于ki,但都大于k(i-1)B-Tree中的每个节点根据实际情况可以包含大量的关键字信息和分支,如下图所示为一个3阶的B-Tree:

    每个节点占用一个盘块的磁盘空间,一个节点上有两个升序排序的关键字和三个指向子树根节点的指针,指针存储的是子节点所在磁盘块的地址。两个关键词划分成的三个范围域对应三个指针指向的子树的数据的范围域。
    以根节点为例,关键字为17和35,P1指针指向的子树的数据范围为小于17,P2指针指向的子树的数据范围为17~35,P3指针指向的子树的数据范围为大于35。模拟查找关键字29的过程:

1. 根据根节点找到磁盘块1,读入内存。【磁盘I/O操作第1次】

2. 比较关键字29在区间(17,35),找到磁盘块1的指针P2。

3. 根据P2指针找到磁盘块3,读入内存。【磁盘I/O操作第2次】

4. 比较关键字29在区间(26,30),找到磁盘块3的指针P2。

5. 根据P2指针找到磁盘块8,读入内存。【磁盘I/O操作第3次】

6. 在磁盘块8中的关键字列表中找到关键字29。分析上面过程,发现需要3次磁盘I/O操作,和3次内存查找操作。由于内存中的关键字是一个有序表结构,可以利用二分法查找提高效率。而3次磁盘I/O操作是影响整个B-Tree查找效率的决定因素。B-Tree相对于AVLTree缩减了节点个数,使每次磁盘I/O取到内存的数据都发挥了作用,从而提高了查询效率。

三、B+Tree

 

  • B+Tree是在B-Tree基础上的一种优化,使其更适合实现外存储索引结构,InnoDB存储引擎就是用B+Tree实现其索引结构。
     
    从上面的B-Tree结构图中可以看到每个节点中不仅包含数据的key值,还有data值。而每一个页的存储空间是有限的,如果data数据较大时将会导致每个节点(即一个页)能存储的key的数量很小,当存储的数据量很大时同样会导致B-Tree的深度较大,增大查询时的磁盘I/O次数,进而影响查询效率。在B+Tree中,所有数据记录节点都是按照键值大小顺序存放在同一层的叶子节点上,而非叶子节点上只存储key值信息,这样可以大大加大每个节点存储的key值数量,降低B+Tree的高度。

B+Tree相对于B-Tree有几点不同:

1. 非叶子节点只存储键值信息。

2. 所有叶子节点之间都有一个链指针。

3. 数据记录都存放在叶子节点中。将上一节中的B-Tree优化,由于B+Tree的非叶子节点只存储键值信息,假设每个磁盘块能存储4个键值及指针信息,则变成B+Tree后其结构如下图所示: 

  • 通常在B+Tree上有两个头指针,一个指向根节点,另一个指向关键字最小的叶子节点,而且所有叶子节点(即数据节点)之间是一种链式环结构。
     
    因此可以对B+Tree进行两种查找运算:一种是对于主键的范围查找和分页查找,另一种是从根节点开始,进行随机查找。

  • 可能上面例子中只有22条数据记录,看不出B+Tree的优点,下面做一个推算:

  • InnoDB存储引擎中页的大小为16KB,一般表的主键类型为INT(占用4个字节)或BIGINT(占用8个字节),指针类型也一般为4或8个字节,也就是说一个页(B+Tree中的一个节点)中大概存储16KB/(8B+8B)=1K个键值(因为是估值,为方便计算,这里的K取值为〖10〗^3)。也就是说一个深度为3的B+Tree索引可以维护10^3 * 10^3 * 10^3 = 10亿 条记录。

  • 实际情况中每个节点可能不能填充满,因此在数据库中,B+Tree的高度一般都在2~4层。mysql的InnoDB存储引擎在设计时是将根节点常驻内存的,也就是说查找某一键值的行记录时最多只需要1~3次磁盘I/O操作。

  • 数据库中的B+Tree索引可以分为聚集索引(clustered index)和辅助索引(secondary index)。上面的B+Tree示例图在数据库中的实现即为聚集索引,聚集索引的B+Tree中的叶子节点存放的是整张表的行记录数据。辅助索引与聚集索引的区别在于辅助索引的叶子节点并不包含行记录的全部数据,而是存储相应行数据的聚集索引键,即主键。当通过辅助索引来查询数据时,InnoDB存储引擎会遍历辅助索引找到主键,然后再通过主键在聚集索引中找到完整的行记录数据。

B-Tree 和 B+Tree的更多相关文章

  1. B-Tree、B+Tree和B*Tree

    B-Tree(这儿可不是减号,就是常规意义的BTree) 是一种多路搜索树: 1.定义任意非叶子结点最多只有M个儿子:且M>2: 2.根结点的儿子数为[2, M]: 3.除根结点以外的非叶子结点 ...

  2. 【Luogu1501】Tree(Link-Cut Tree)

    [Luogu1501]Tree(Link-Cut Tree) 题面 洛谷 题解 \(LCT\)版子题 看到了顺手敲一下而已 注意一下,别乘爆了 #include<iostream> #in ...

  3. 【BZOJ3282】Tree (Link-Cut Tree)

    [BZOJ3282]Tree (Link-Cut Tree) 题面 BZOJ权限题呀,良心luogu上有 题解 Link-Cut Tree班子提 最近因为NOIP考炸了 学科也炸了 时间显然没有 以后 ...

  4. [LeetCode] Encode N-ary Tree to Binary Tree 将N叉树编码为二叉树

    Design an algorithm to encode an N-ary tree into a binary tree and decode the binary tree to get the ...

  5. 平衡二叉树(Balanced Binary Tree 或 Height-Balanced Tree)又称AVL树

    平衡二叉树(Balanced Binary Tree 或 Height-Balanced Tree)又称AVL树 (a)和(b)都是排序二叉树,但是查找(b)的93节点就需要查找6次,查找(a)的93 ...

  6. WPF中的Visual Tree和Logical Tree与路由事件

    1.Visual Tree和Logical TreeLogical Tree:逻辑树,WPF中用户界面有一个对象树构建而成,这棵树叫做逻辑树,元素的声明分层结构形成了所谓的逻辑树!!Visual Tr ...

  7. 笔试算法题(39):Trie树(Trie Tree or Prefix Tree)

    议题:TRIE树 (Trie Tree or Prefix Tree): 分析: 又称字典树或者前缀树,一种用于快速检索的多叉树结构:英文字母的Trie树为26叉树,数字的Trie树为10叉树:All ...

  8. LC 431. Encode N-ary Tree to Binary Tree 【lock,hard】

    Design an algorithm to encode an N-ary tree into a binary tree and decode the binary tree to get the ...

  9. 将百分制转换为5分制的算法 Binary Search Tree ordered binary tree sorted binary tree Huffman Tree

    1.二叉搜索树:去一个陌生的城市问路到目的地: for each node, all elements in its left subtree are less-or-equal to the nod ...

  10. WPF中Logical Tree和Visual Tree的区别

    The Logical TreeThe logical tree describes the relations between elements of the user interface. The ...

随机推荐

  1. shell的while和until 的用法

    shell while循环工作中使用的不多,一般适用于守护进程程序或始终循环执行场景,其他循环计算等. while条件句: 语法: while 条件 do 指令… done ok,我们测试一下: 测试 ...

  2. Ubuntu 无法进行SSH连接,开启22端口

    我们在VM中安装好Ubuntu 虚拟机后,经常需要使用Xshell等工具进行远程连接,但是会出现无法连接的问题,原因是Ubuntu中默认关闭了SSH 服务. 1. 查看Ubuntu虚拟机IP地址: 命 ...

  3. 【汤鸿鑫 3D太极】5年目标规划(基本功、套路、实战搏击)

    [5年目标]在基本功的基础上,每年完成一个套路或实战搏击的学习研究. [中小学2年]三段九节 + 2套路. [高中的3年]太极十三势 + 1套路 + 推手 + 搏击. 1.中小学阶段-可自学 (1)基 ...

  4. Kafka 0.11新功能介绍:空消费组延迟rebalance

    Kafka 0.11新功能介绍:空消费组延迟rebalance 在0.11之前的版本中,多个consumer实例加入到一个空消费组将导致多次的rebalance,这是由于每个consumer inst ...

  5. 数据库的连接、会话与SQLite

    通俗来讲,会话(Session) 是通信双方从开始通信到通信结束期间的一个上下文(Context).这个上下文是一段位于服务器端的内存:记录了本次连接的所有相关状态和运行数据. 连接(Connecti ...

  6. [Android] ScrollView can host only one direct child

    android 采用ScrollView布局时出现异常:ScrollView can host only one direct child.主要是ScrollView内部只能有一个子元素,即不能并列两 ...

  7. python 中的__init__.py的用法与个人理解

    使用Python模块常见的情况是,事先写好A.py文件,需要import B.py文件时,先拷贝到当前目录,然后再import 这样的做法在程序量较小的情况下是可行的,如果程序交互复杂程度稍高,就很费 ...

  8. 转://Oracle中User和Schema的区别和联系

    今天在阅读Oracle官方文档的时候,读到schema的基本概念,这就让我产生了一个疑问:user和schema两者之间到底有什么区别?为了更深层次的理解二者之间的区别和联系,以下是官方文档中关于us ...

  9. 应对WannaCry勒索危机之关闭445端口等危险端口——以本人Windows7系统为例

    应对WannaCry勒索危机之关闭445端口等危险端口--以本人Windows7系统为例 近日,全球范围内爆发WannaCry勒索病毒危机 我国很多大学纷纷中招.受灾严重,甚至连刘老师的电脑也-- 拿 ...

  10. extjs 中的一些鲜为人知的属性(深渊巨坑)

    1. new Ext.form.FormPanel  组件中,去除边框属性为:baseCls:'my-panel-no-border', 2.当 new Ext.form.FormPanel  嵌套b ...