B+/-Tree原理

B-Tree介绍
B-Tree是一种多路搜索树(并不是二叉的):
       1.定义任意非叶子结点最多只有M个儿子;且M>2;
       2.根结点的儿子数为[2, M];
       3.除根结点以外的非叶子结点的儿子数为[M/2, M];
       4.每个结点存放至少M/2-1(取上整)和至多M-1个关键字;(至少2个关键字)
       5.非叶子结点的关键字个数=指向儿子的指针个数-1;
       6.非叶子结点的关键字:K[1], K[2], …, K[M-1];且K[i] < K[i+1];
       7.非叶子结点的指针:P[1], P[2], …, P[M];其中P[1]指向关键字小于K[1]的子树,P[M]指向关键字大于K[M-1]的子树,其它P[i]指向关键字属于(K[i-1], K[i])的子树;
       8.所有叶子结点位于同一层;

       如:(M=3)

        

B-树的特性:
       1.关键字集合分布在整颗树中;
       2.任何一个关键字出现且只出现在一个结点中;
       3.搜索有可能在非叶子结点结束;
       4.其搜索性能等价于在关键字全集内做一次二分查找;
       5.自动层次控制;

B-树的搜索:

     从根结点开始,对结点内的关键字(有序)序列进行二分查找,如果命中则结束,否则进入查询关键字所属范围的儿子结点;重复,直到所对应的儿子指针为空,或已经是叶子结点;

B-树的插入:
    首先在最低层的某个非终端结点中添加一个关键字,若该结点的关键字个数不超过M-1,则插入完成,否则要产生结点的“分裂”,
B-树的删除:
    (1)被删关键字所在结点中的关键字数目不小于ceil(M/2),则只需从该结点中删去该关键字K[i]和相应指针P[i],树的其它部分不变
    (2)被删关键字所在结点中的关键字数目等于ceil(M/2)-1,而与该结点相邻的右兄弟(或左兄弟)结点中的关键字数目大于ceil(M/2)-1,则需将其兄弟结点中的最小(或最大)的关键字上移至双亲结点中,而将双亲结点中小于(或大于)且紧靠该上移关键字的关键字下移至被删关键字所在结点中。
     (3)被删关键字所在结点和其相邻的兄弟结点中的关键字数目均等于ceil(M/2)-1。假设该结点有右兄弟,且其右兄弟结点地址由双亲结点中的指针Ai所指,则在删去关键字之后,它所在结点中剩余的关键字和指针,加上双亲结点中的关键字Ki一起,合并到 Ai所指兄弟结点中(若没有右兄弟,则合并至左兄弟结点中)。


B+Tree介绍

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

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

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

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

       5.为所有叶子结点增加一个链指针;

       6.所有关键字都在叶子结点出现;

       如:(M=3)


B+的搜索与B-树也基本相同,区别是B+树只有达到叶子结点才命中(B-树可以在非叶子结点命中),其性能也等价于在关键字全集做一次二分查找;

       B+的特性:

       1.所有关键字都出现在叶子结点的链表中(稠密索引),且链表中的关键字恰好是有序的;

       2.不可能在非叶子结点命中;

       3.非叶子结点相当于是叶子结点的索引(稀疏索引),叶子结点相当于是存储(关键字)数据的数据层;

       4.更适合文件索引系统;


在linux中xfs文件全B+树ext4 文件索引是B+树,但目录索引是bitmap


MySQL索引实现
    在MySQL中,索引属于存储引擎级别的概念,不同存储引擎对索引的实现方式是不同的,本文主要讨论MyISAM和InnoDB两个存储引擎的索引实现方式。
    MyISAM索引实现
      MyISAM引擎使用B+Tree作为索引结构,叶节点的data域存放的是数据记录的地址。下图是MyISAM索引的原理图:

这里设表一共有三列,假设我们以Col1为主键,则图8是一个MyISAM表的主索引(Primary key)示意。可以看出MyISAM的索引文件仅仅保存数据记录的地址。在MyISAM中,主索引和辅助索引(Secondary key)在结构上没有任何区别,只是主索引要求key是唯一的,而辅助索引的key可以重复。如果我们在Col2上建立一个辅助索引,则此索引的结构如下图所示:

同样也是一颗B+Tree,data域保存数据记录的地址。因此,MyISAM中索引检索的算法为首先按照B+Tree搜索算法搜索索引,如果指定的Key存在,则取出其data域的值,然后以data域的值为地址,读取相应数据记录。


MyISAM的索引方式也叫做“非聚集”的,之所以这么称呼是为了与InnoDB的聚集索引区分。


InnoDB索引实现

      虽然InnoDB也使用B+Tree作为索引结构,但具体实现方式却与MyISAM截然不同。

      第一个重大区别是InnoDB的数据文件本身就是索引文件。从上文知道,MyISAM索引文件和数据文件是分离的,索引文件仅保存数据记录的地址。而在InnoDB中,表数据文件本身就是按B+Tree组织的一个索引结构,这棵树的叶节点data域保存了完整的数据记录。这个索引的key是数据表的主键,因此InnoDB表数据文件本身就是主索引。

上图是InnoDB主索引(同时也是数据文件)的示意图,可以看到叶节点包含了完整的数据记录。这种索引叫做聚集索引。因为InnoDB的数据文件本身要按主键聚集,所以InnoDB要求表必须有主键(MyISAM可以没有),如果没有显式指定,则MySQL系统会自动选择一个可以唯一标识数据记录的列作为主键,如果不存在这种列,则MySQL自动为InnoDB表生成一个隐含字段作为主键,这个字段长度为6个字节,类型为长整形。

  第二个与MyISAM索引的不同是InnoDB的辅助索引data域存储相应记录主键的值而不是地址。换句话说,InnoDB的所有辅助索引都引用主键作为data域。例如,下图为定义在Col3上的一个辅助索引:

这里以英文字符的ASCII码作为比较准则。聚集索引这种实现方式使得按主键的搜索十分高效,但是辅助索引搜索需要检索两遍索引:首先检索辅助索引获得主键,然后用主键到主索引中检索获得记录。

  了解不同存储引擎的索引实现方式对于正确使用和优化索引都非常有帮助,例如知道了InnoDB的索引实现后,就很容易明白为什么不建议使用过长的字段作为主键,因为所有辅助索引都引用主索引,过长的主索引会令辅助索引变得过大。再例如,用非单调的字段作为主键在InnoDB中不是个好主意,因为InnoDB数据文件本身是一颗B+Tree,非单调的主键会造成在插入新记录时数据文件为了维持B+Tree的特性而频繁的分裂调整,十分低效,而使用自增字段作为主键则是一个很好的选择。

为什么选用B+/-Tree

一般来说,索引本身也很大,不可能全部存储在内存中,因此索引往往以索引文件的形式存储的磁盘上。这样的话,索引查找过程中就要产生磁盘I/O消耗,相对于内存存取,I/O存取的消耗要高几个数量级,所以评价一个数据结构作为索引的优劣最重要的指标就是在查找过程中磁盘I/O操作次数的渐进复杂度。换句话说,索引的结构组织要尽量减少查找过程中磁盘I/O的存取次数。

简单点说说内存读取,内存是由一系列的存储单元组成的,每个存储单元存储固定大小的数据,且有一个唯一地址。当需要读内存时,将地址信号放到地址总线上传给内存,内存解析信号并定位到存储单元,然后把该存储单元上的数据放到数据总线上,回传。

写内存时,系统将要写入的数据和单元地址分别放到数据总线和地址总线上,内存读取两个总线的内容,做相应的写操作。

内存存取效率,跟次数有关,先读取A数据还是后读取A数据不会影响存取效率。而磁盘存取就不一样了,磁盘I/O涉及机械操作。磁盘是由大小相同且同轴的圆形盘片组成,磁盘可以转动(各个磁盘须同时转动)。磁盘的一侧有磁头支架,磁头支架固定了一组磁头,每个磁头负责存取一个磁盘的内容。磁头不动,磁盘转动,但磁臂可以前后动,用于读取不同磁道上的数据。磁道就是以盘片为中心划分出来的一系列同心环(如图标红那圈)。磁道又划分为一个个小段,叫扇区,是磁盘的最小存储单元。

磁盘读取时,系统将数据逻辑地址传给磁盘,磁盘的控制电路会解析出物理地址,即哪个磁道哪个扇区。于是磁头需要前后移动到对应的磁道,消耗的时间叫寻道时间,然后磁盘旋转将对应的扇区转到磁头下,消耗的时间叫旋转时间。所以,适当的操作顺序和数据存放可以减少寻道时间和旋转时间。
为了尽量减少I/O操作,磁盘读取每次都会预读,大小通常为页的整数倍。即使只需要读取一个字节,磁盘也会读取一页的数据(通常为4K)放入内存,内存与磁盘以页为单位交换数据。因为局部性原理认为,通常一个数据被用到,其附近的数据也会立马被用到。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 索引的底层实现原理包括: A. B树(B-Tree) B. B+树(B+Tree) C. Hash索引 索引的优化包括: D. 索引分裂 E. 索引合并 F. 索引重建 G. 索引维护(如更新、删除、插入操作) H. 索引优化器(Optimizer)的使用 所以正确答案是: A、B、D、E、F、G、H。 ### 回答2: 索引的底层实现原理是利用数据库中的数据结构,将数据表的某一列或多列按照特定的规则进行排序存储,以便快速查找和访问数据。 优化索引可以从以下几个方面进行: A. B树索引结构优化: B树是索引最常用的数据结构,可以通过调整B树的阶数来优化索引性能。阶数越大,每层节点存储的索引范围就越大,减少了IO操作次数,提高了查询效率。另外,可以使用自适应索引结构,根据查询频率和数据分布情况来自动调整B树的阶数,进一步优化索引性能。 B. B+树叶节点优化: B+树的叶节点存储了数据的真实地址,可以通过增加叶子节点的指针个数来减少IO操作次数,提高查询效率。同时,可以将热点数据放在B+树的叶节点中,以提高查询的命中率,减少磁盘访问次数。 C. B*树分裂策略优化: B*树相对于B树来说有更好的索引性能,可以通过调整分裂策略来进一步优化索引。例如,可以采用快速分裂策略,当某一节点需要分裂时,直接将该节点的部分键移动到新节点,避免了整体数据的复制,提高了分裂的效率。 D. B/树索引压缩优化: B/树是基于B树的变种索引结构,可以通过对索引节点的压缩来减少存储空间的占用。压缩策略可以采用字典压缩、前缀压缩等方法,将相似的键值合并存储,减少了磁盘IO操作,提高了索引的查询性能。 综上所述,索引的底层实现原理是利用特定的数据结构进行快速访问,而优化索引可以通过调整树结构、节点存储方式、分裂策略和压缩方法等手段来提高索引的性能。 ### 回答3: 索引的底层实现原理是通过数据结构来存储和管理数据库中的索引数据。常用的索引实现方式有B+树、哈希表和位图等。 B+树是一种常用的索引结构,其优点是适应范围查询和有序性查询,其在数据库中有广泛的应用。B+树通过在每个非叶子节点存储多个关键字和指针来提高查询效率,同时通过叶子节点的链表来实现有序性查询。B+树的查询、插入和删除操作都能够在O(logN)的时间复杂度内完成,因此被广泛应用于数据库中。 哈希表是另一种常见的索引实现方式,它通过将关键字通过哈希函数映射到哈希表中的位置来加快索引的查找速度。哈希表的查询效率非常高,可以在O(1)的时间复杂度内完成。但是哈希表不支持范围查询和有序性查询,同时对哈希冲突的处理也会增加其操作的复杂性。 位图索引是一种特殊的索引结构,用于处理数据中的布尔类型属性(如性别、职业等),通过对每个属性值使用一个位来表示是否存在,从而实现了高效的布尔操作。位图索引占用的存储空间相对较小,但对于数据的更新操作会有一定的影响。 综上所述,索引的底层实现原理主要有B+树、哈希表和位图等,每种实现方式都有其适用的场景和优化方式。根据具体的应用需求和数据特性,选择合适的索引实现方式以及相应的优化策略可以提高数据库的查询性能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值