数据结构与算法-13高级数据结构_树论(Btree&B+Tree)

Btree&B+Tree

1 btree-定义

在这里插入图片描述

B-树是一种自平衡的树形数据结构,它能够保持数据的有序性,并允许搜索、顺序访问、插入和删除操作都在对数时间内完成。与二叉树不同,B-树的每个节点可以拥有多于两个的子节点,这取决于树的阶(order)或度数(degree)。阶为M的B-树意味着:

  • 每个节点最多有M个子节点。
  • 每个非根节点至少有⌈M/2⌉个子节点(向上取整),根节点至少有两个子节点(除非它是叶子节点)。
  • 每个节点中的关键字数量比其子节点数量少一。即,如果节点有N个子节点,那么它将包含N-1个关键字。
  • 所有叶子节点都位于同一层,并且不包含任何子节点或关键字之间的指针,但它们可能包含指向实际数据记录的指针。
  • 关键字在节点内以升序排列,并且每个子树中的所有关键字都小于其父节点中分隔该子树的关键字,而大于分隔其左侧子树的关键字(如果存在的话)。

2 btree特性

  1. 多路搜索:B-树通过允许多个分支(子节点)来减少树的高度,这使得搜索过程更加高效。在每次搜索中,B-树可以排除掉更多的分支,从而更快地定位到目标关键字。
  2. 自平衡性:B-树在插入和删除操作时通过分裂和合并节点来保持树的平衡。这种平衡调整确保了树的高度始终保持在一个合理的范围内,从而保证了操作的效率。
  3. 磁盘友好:由于B-树的节点可以包含多个关键字和子节点,因此每个节点可以映射到磁盘上的一个单独块(block)。这使得B-树特别适合用于存储在磁盘上的大量数据,因为它可以显著减少磁盘I/O操作的次数。
  4. 范围查询:B-树的节点按关键字顺序排列,这使得范围查询变得非常高效。通过简单地遍历叶子节点或内部节点,B-树可以快速地返回指定范围内的所有关键字。
  5. 支持大量数据:由于B-树的高度较低且每个节点可以包含大量关键字,因此它能够高效地处理大量数据。这使得B-树成为数据库索引、文件系统和操作系统中常用的数据结构。
  6. 动态数据结构:B-树是动态数据结构,可以随着数据的插入和删除而增长和缩小。通过适当的分裂和合并操作,B-树可以保持其平衡性,同时保持其高效性。
  7. 支持重复键值:虽然B-树通常用于存储唯一的键值,但它也可以轻松地适应包含重复键值的情况。在这种情况下,可以在节点中存储相同关键字的多个实例,或者在叶子节点中使用额外的结构(如链表)来存储具有相同关键字的记录。

3 b+tree-定义

在这里插入图片描述

B+树是一种n叉排序树,每个节点通常有多个孩子。一棵B+树包含根节点、内部节点和叶子节点。B+树是B树的一种变形形式,但与B树相比,它在结构上有所优化。阶为M的B+树意味着:

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

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

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

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

(5)叶节点的高度一致:这个的 好处是什么?

  • 所有叶节点具有相同的高度。这一特性带来的好处包括:
    • 简化查询操作:由于所有叶节点位于同一层,查询操作在到达叶节点之前所经过的路径长度是固定的,这有助于简化查询算法的实现。
    • 优化范围查询:由于叶节点之间通过指针相连,且所有叶节点位于同一层,因此可以非常高效地执行范围查询操作,只需遍历叶节点链表即可。
    • 提高缓存效率:由于树的高度较低且叶节点位于同一层,因此可以更有效地利用缓存来存储树的结构和数据,从而提高数据访问速度。

4 b+tree特性

  1. 所有值都在叶子节点,且叶子节点相连
    • B+树的所有数据记录都存储在叶子节点上,而非叶子节点仅作为索引存在,不存储实际的数据记录。这种设计使得非叶子节点能够容纳更多的关键字,从而减少了树的高度,提高了查找效率。
    • 叶子节点之间通过指针相连,形成了一个有序链表。这种结构使得B+树在进行范围查询和顺序访问时非常高效,因为可以直接在叶子节点之间移动,而无需回溯到上层节点。
  2. 内部节点仅包含索引信息
    • B+树的内部节点(非叶子节点)仅包含其子节点中的最大(或最小)关键字作为索引,这些索引用于指导查找过程。由于内部节点不包含数据记录,因此它们可以更加紧凑地存储索引信息,进一步减少树的高度。
  3. 节点分裂与合并保持树的平衡
    • 当叶子节点中的关键字数量超过一定限制时,该节点会进行分裂操作,将部分关键字和子节点指针提升到父节点中,并创建一个新的叶子节点来存储剩余的关键字和子节点指针。这样可以保持树的高度稳定,避免因为单个节点过大而导致的性能下降。
    • 类似地,当因为删除操作导致叶子节点中的关键字数量过少时,可能会与相邻的节点进行合并操作,以维持树的平衡。
  4. 自底向上的插入和删除操作
    • 在B+树中插入新元素时,通常是从叶子节点开始进行的。首先找到应该插入新元素的叶子节点,并在其中插入新元素。如果插入后叶子节点的关键字数量超过了限制,则会进行分裂操作,并可能触发上层节点的调整。
    • 删除操作也是类似的,首先找到包含要删除关键字的叶子节点,并从中删除该关键字。如果删除后叶子节点的关键字数量过少,则可能会与相邻的节点进行合并操作。
  5. 稳定的对数时间复杂度
    • 由于B+树的高度较低且保持平衡,因此其插入、删除和查找操作都具有稳定的对数时间复杂度。这意味着无论树的大小如何变化,这些操作的时间开销都保持在较低的水平。
  6. 磁盘I/O操作的优化
    • B+树的设计特别考虑了磁盘I/O操作的优化。由于非叶子节点不存储数据记录且节点分裂和合并操作较为频繁地发生在叶子节点之间,因此可以更加有效地利用磁盘的块(block)大小来减少I/O操作的次数。
    • 此外,由于叶子节点之间通过指针相连且有序排列,因此可以更加高效地进行顺序访问和范围查询操作。

5 b+tree&数据库

5.1 B+Tree的阶数与数据库

阶数的重要性

B+Tree的阶数(即节点中可存储的键值对数)对数据库的查找效率和性能有着至关重要的影响。阶数决定了每个节点能够存储的键值对数量,进而影响到树的深度和查询时需要遍历的节点数。

阶数的设定

  • 影响要素
    • 页大小:MySQL中B+Tree的阶数主要由页大小决定。MySQL的InnoDB存储引擎默认页大小为16KB。即b+tree一个节点可以存储的数据未16KB
    • 数据类型:索引字段的数据类型也会影响每个节点能存储的键值对数量。例如,bigint类型的主键字段占用8字节,加上指针(通常也占用一定空间,如4字节),共同决定了每个节点能存储的键值对数量。
  • 计算示例
    • 单个键值对占用的空间:假设主键为bigint类型(8字节),加上指针(4字节),则每个键值对占用8B + 4B = 12B
    • 一页能存储的键值对数量16KB / 12B ≈ 1333(实际计算中可能因页内其他开销而略有不同,此处为简化计算)。但考虑到对齐和页内其他信息(如页头、页尾等),实际可存储的键值对数量会小于这个值。为了简化说明,我们可以假设为1024(即1K)。
    • 计算一下高度为3,阶数为4的b+tree可以存放多少个索引?1024 * 1024 * 1024

总结

​ 在MySQL中,B+Tree的阶数由页大小数据类型共同决定。通过合理设定页大小和选择合适的数据类型,可以优化B+Tree的阶数,进而提高数据库的查询效率和性能。尽管实际中阶数可能受到多种因素的影响而难以达到理论最大值,但MySQL的InnoDB存储引擎通过其高效的索引结构和算法,确保了即使在大量数据的情况下也能保持较高的查询效率。

5.2 从b+tree看复合索引

什么是复合索引?

在MySQL中,复合索引(也称为联合索引)是由两个或更多列组成的索引。这种索引结构对于优化涉及多个列的查询非常有效,因为它能够同时利用多个列的值来快速定位数据。

复合索引的组成原理

  • B+树是一种自平衡的树数据结构,它保持数据排序,允许搜索、顺序访问、插入和删除操作都在对数时间内完成。在复合索引中,B+树的每个节点都会包含索引列的值,这些值按照索引列在索引定义中的顺序进行排序。
  • 索引列的排序:复合索引中的列按照索引创建时指定的顺序进行排序。这意味着,B+树中的每个节点都会首先根据第一列的值进行排序,如果第一列的值相同,则根据第二列的值进行排序,以此类推。
  • 最左前缀原则:复合索引的一个重要特性是遵循最左前缀原则。这意味着,如果查询条件中包含了复合索引的最左边的列(或这些列的前缀),那么MySQL就可以利用这个复合索引来加速查询。然而,如果查询条件跳过了索引的最左列,那么索引可能不会被使用,除非查询优化器能够找到其他利用索引的方式。
  • 索引的覆盖:如果复合索引包含了查询需要的所有列,那么查询就可以直接从索引中检索数据,而无需回表查询数据行。这种查询方式称为索引覆盖扫描,可以显著提高查询效率。

在这里插入图片描述

复合索引的失效

  1. 查询条件不符合最左前缀原则:如前所述,如果查询条件没有包含复合索引的最左列(或这些列的前缀),那么索引可能不会被使用。
  2. 索引列参与了计算或函数操作:如果在查询条件中对索引列进行了计算或使用了函数,那么MySQL可能无法有效利用索引。例如,如果索引列是age,而查询条件是YEAR(CURDATE()) - age > 18,那么索引可能不会被使用。
  3. 数据类型不匹配:如果查询条件中的数据类型与索引列的数据类型不匹配,那么MySQL可能无法将查询条件与索引列进行有效比较,从而导致索引失效。
  4. 索引列的数据分布不均匀:如果复合索引中的某个列的数据分布非常不均匀,那么该索引的效果可能会大打折扣。因为索引的主要目的是减少需要扫描的数据量,如果某个列的值非常集中,那么索引可能无法有效过滤掉大部分数据。
  5. 查询优化器的选择:MySQL的查询优化器会基于成本估算来选择执行计划。在某些情况下,即使存在复合索引,优化器也可能认为使用全表扫描或其他索引更为高效。这可能是由于统计信息不准确、索引选择性差或其他查询条件的影响。
  6. 多表连接查询:在涉及多个表的连接查询中,复合索引的使用可能会受到限制。如果连接条件没有直接利用到复合索引中的列,或者连接操作导致索引失效(如使用了笛卡尔积连接),那么复合索引可能无法被有效利用。
5.3 索引建立的基本原则
  1. 索引数量控制

    • 避免过多索引:因为B+Tree的插入和删除操作需要维护索引,过多的索引会显著降低数据插入速度,增加数据库的维护成本。
  2. 避免使用LIKE ‘%%’

    • LIKE '%%'的索引失效:当在查询条件中使用LIKE '%%'时,索引无法被有效利用,因为该模式匹配会扫描全表。
  3. 字段类型与大小

    • 字段类型与索引效率:索引字段类型不宜过大,字段越小,B+Tree的阶数(即节点内键值对的数量)越大,查询效率越高。例如,intbigintvarchar(10)varchar(100)textlongtext等类型,应根据实际数据量和查询需求选择。

    • 全文索引:对于大文本字段,考虑使用全文索引来提高搜索效率。

  4. 字段值的离散性

    • 避免低离散度字段索引:对于离散度很低的字段(如性别),建立索引可能效果不佳,因为索引中大量键值相同,无法有效过滤数据。
  5. 联合索引的最左匹配原则

    • 最左前缀原则:MySQL在解析查询时,会利用联合索引的最左前缀进行匹配。例如,若对(id, name, age)建立索引,则查询SELECT * FROM user WHERE name = '赵云' AND id = 1会利用索引,但查询SELECT * FROM user WHERE name = '赵云' AND age = 10虽然也使用了索引的一部分,但效率可能不如完全匹配。

    • 自动优化:MySQL查询优化器会尝试自动优化查询,以利用最合适的索引。

  6. NOT IN的使用与限制

    • NOT IN与索引NOT IN子句在包含大量值时可能不会走索引,因为优化器可能认为全表扫描更高效。

    • 值数量限制:当IN子句中的值过多时,MySQL可能会报错或性能下降,需要根据实际情况调整查询策略或优化数据库配置。

6 btree与b+tree的比较

B+树是B树的一种变型,它们在结构上存在一些差异。相比B树,B+树更适合实际应用中的数据库索引和文件索引,主要原因包括:

6.1 数据存储结构
  • BTree
    • 数据项(或记录的一部分)既可以存储在非叶子节点,也可以存储在叶子节点中。
    • 这种结构使得BTree在查询时可能在非叶子节点就找到所需的数据项,但在某些情况下也可能需要遍历到叶子节点。
  • B+Tree
    • 所有数据项(或记录)都存储在叶子节点中,形成一个有序链表,非叶子节点仅作为索引存在,不存储实际的数据记录。
    • 这种设计确保了所有查找操作最终都会落在叶子节点上。同时,非叶子节点不存储数据,减少了磁盘I/O次数。
    • 查询效率稳定:在B+树中,任何关键字的查询都必须从根节点走到叶子节点,查询路径长度相同,这保证了查询效率的稳定性。
6.2 叶子节点的连接性
  • BTree:叶子节点之间通常没有直接的连接,它们是相互独立的。
  • B+Tree:所有叶子节点通过指针相互连接,形成一个双向链表。这种设计优化了范围查询的性能,因为可以顺序遍历叶子节点链表而无需回溯。
6.3 磁盘I/O效率
  • BTree:由于数据项可能存储在非叶子节点,BTree在某些情况下可以减少磁盘I/O次数。但随着树深度的增加,特别是在处理大量数据时,I/O成本可能会显著增加。
  • B+Tree:由于所有数据都存储在叶子节点,并且叶子节点之间形成了有序链表,B+Tree通常具有更低的树高,从而减少了磁盘I/O次数。这使得B+Tree在处理大量数据时具有更高的效率。
6.4 节点分裂与合并
  • 两者相似:在节点分裂和合并方面,BTree和B+Tree都遵循类似的规则来保持树的平衡。当节点中的数据项数量超过或低于某个阈值时,会进行相应的分裂或合并操作。
  • 26
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值