热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

MySQL中的B+树索引结构

B树B树(B-tree、B-树):是一种平衡的多路搜索树,多用于文件系统、数据库的实现。B树的特点:1个节点可以存储超过2个元素、可以拥有超过2个子节点;拥有二叉搜索树的一些性质(
B树

B树(B-tree、B-树):是一种平衡的多路搜索树,多用于文件系统、数据库的实现。

B树的特点:

  • 1个节点可以存储超过2个元素、可以拥有超过2个子节点;

  • 拥有二叉搜索树的一些性质(有序性);

  • 平衡,每个节点的所有子树高度一致;

  • 树的整体高度较低。

m阶B树的性质(m≥2)

m阶表示节点允许有m个子节点,节点元素的个数可以有m-1个。

3阶B树:

《MySQL中的B+树索引结构》

4阶B树:

《MySQL中的B+树索引结构》

B+树

B+树是B树的一种变形形式,B+树上的叶子结点存储关键字以及相应记录
的地址,叶子结点以上各层作为索引使用。

《MySQL中的B+树索引结构》

从上图我们可以归纳出B+树的几个特征:

  • 所有记录节点都是按键值的大小顺序存放在同一层的叶子节点上,由各叶子节点
    指针进行连接;

  • 相同节点数量的情况下,B+树高度远低于平衡二叉树;

  • 非叶子节点只保存索引信息和下一层节点的指针信息,不保存实际数据
    记录;

  • 只有叶子节点存储实际的数据。

B+树的变体为B树,在B+树的非根和非叶子结点再增加指向兄弟的指针;
B
树定义了非叶子结点关键字个数至少为(2/3)*M,即块的最低使用率为2/3(代
替 B+树的1/2)。

MySQL中的B+树索引结构

B+树索引是数据库系统中最为常见的一种索引数据结构,几乎所有的关系型数据库都支持它。

那为什么关系型数据库都热衷支持B+树索引呢?因为它是目前为止排序最有效率的数据结构。像二叉树,哈希索引、红黑树、SkipList,在海量数据基于磁盘存储效率方面远不如B+树索引高效。

所以,上述的数据结构一般仅用于内存对象,基于磁盘的数据排序与存储,最有效的依然是B+树索引。

B+树索引的特点是: 基于磁盘的平衡树,但树非常矮,通常为3~4层,能存放千万到上亿的排序数据。树矮意味着访问效率高,从千万或上亿数据里查询一条数据,只用 3、4 次I/O。

又因为现在的固态硬盘每秒能执行至少10000次I/O,所以查询一条数据,哪怕全部在磁盘上,也只需要0.0030.004秒。另外,因为B+树矮,在做排序时,也只需要比较34次就能定位数据需要插入的位置,排序效率非常不错。

B+树索引由根节点(root node)、中间节点(non leaf node)、叶子节点(leaf node)组成,其中叶子节点存放所有排序后的数据。当然也存在一种比较特殊的情况,比如高度为1的B+树索引:

《MySQL中的B+树索引结构》

上图中,第一个列就是B+树索引排序的列,你可以理解它是表User中的列id,类型为8字节的BIGINT,所以列userId就是索引键(key),类似下表:

CREATE TABLE User (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(128) NOT NULL,
sex CHAR(6) NOT NULL,
registerDate DATETIME NOT NULL,
...
)

所有B+树都是从高度为1的树开始,然后根据数据的插入,慢慢增加树的高度。你要牢记:索引是对记录进行排序, 高度为1的B+树索引中,存放的记录都已经排序好了,若要在一个叶子节点内再进行查询,只进行二分查找,就能快速定位数据。

可随着插入B+树索引的记录变多,1个页(16K)无法存放这么多数据,所以会发生B+树的分裂,B+树的高度变为 2,当B+树的高度大于等于2时,根节点和中间节点存放的是索引键对,由(索引键、指针)组成。

索引键就是排序的列,而指针是指向下一层的地址,在MySQ 的InnoDB存储引擎中占用6个字节。下图显示了B+树高度为2时,B+树索引的样子:

《MySQL中的B+树索引结构》

可以看到,在上面的B+树索引中,若要查询索引键值为5的记录,则首先查找根节点,查到键值对(20,地址),这表示小于20的记录在地址指向的下一层叶子节点中。接着根据下一层地址就可以找到最左边的叶子节点,在叶子节点中根据二分查找就能找到索引键值为5的记录。

那一个高度为2的B+树索引,理论上最多能存放多少行记录呢?

在 MySQL InnoDB存储引擎中,一个页的大小为16K,在上面的表User中,键值userId是BIGINT类型,则:

根节点能最多存放以下多个键值对 = 16K / 键值对大小(8+6)1100

再假设表User中,每条记录的大小为500字节,则:

叶子节点能存放的最多记录为 = 16K / 每条记录大小 ≈ 32

综上所述,树高度为 2 的 B+ 树索引,最多能存放的记录数为:

总记录数 = 1100 * 32 = 35,200

也就是说,35200条记录排序后,生成的B+树索引高度为2。在35200条记录中根据索引键查询一条记录只需要查询2个页,一个根叶,一个叶子节点,就能定位到记录所在的页。

高度为3的B+树索引本质上与高度2的索引一致,如下图所示,不再赘述:

《MySQL中的B+树索引结构》

同理,树高度为3的 B+ 树索引,最多能存放的记录数为:

总记录数 = 1100(根节点) * 1100(中间节点) * 32 = 38,720,000

讲到这儿,你会发现,高度为3的B+树索引竟然能存放3800W条记录。高度为4的B+树索引就能存放上百亿的记录了,也就意味着在亿级别的数据中查询一条记录,只需要查询4页,也就是4次IO操作。那么B+树索引的优势是否逐步体现出来了呢?

不过,在真实环境中,每个页其实利用率并没有这么高,还会存在一些碎片的情况。

优化B+树索引的插入性能

B+树的查询高效是要付出代价的,也就是在插入时会带来性能问题。

B+ 树在插入时就对要对数据进行排序,但排序的开销其实并没有你想象得那么大,因为排序是CPU操作(当前一个时钟周期CPU能处理上亿指令)。

真正的开销在于B+树索引的维护,保证数据排序,这里存在两种不同数据类型的插入情况。

  • 数据顺序(或逆序)插入: B+ 树索引的维护代价非常小,叶子节点都是从左往右进行插入,比较典型的是自增 ID 的插入、时间的插入(若在自增 ID 上创建索引,时间列上创建索引,则 B+ 树插入通常是比较快的)。

  • 数据无序插入: B+ 树为了维护排序,需要对页进行分裂、旋转等开销较大的操作,另外,即便对于固态硬盘,随机写的性能也不如顺序写,所以磁盘性能也会收到较大影响。比较典型的是用户昵称,每个用户注册时,昵称是随意取的,若在昵称上创建索引,插入是无序的,索引维护需要的开销会比较大。

你不可能要求所有插入的数据都是有序的,因为索引的本身就是用于数据的排序,插入数据都已经是排序的,那么你就不需要B+树索引进行数据查询了。

所以对于B+树索引,在 MySQL 数据库设计中,仅要求主键的索引设计为顺序,比如使用自增,而不用无序值做主键。


推荐阅读
  • SpringBoot uri统一权限管理的实现方法及步骤详解
    本文详细介绍了SpringBoot中实现uri统一权限管理的方法,包括表结构定义、自动统计URI并自动删除脏数据、程序启动加载等步骤。通过该方法可以提高系统的安全性,实现对系统任意接口的权限拦截验证。 ... [详细]
  • 高质量SQL书写的30条建议
    本文提供了30条关于优化SQL的建议,包括避免使用select *,使用具体字段,以及使用limit 1等。这些建议是基于实际开发经验总结出来的,旨在帮助读者优化SQL查询。 ... [详细]
  • RouterOS 5.16软路由安装图解教程
    本文介绍了如何安装RouterOS 5.16软路由系统,包括系统要求、安装步骤和登录方式。同时提供了详细的图解教程,方便读者进行操作。 ... [详细]
  • 本文介绍了一种轻巧方便的工具——集算器,通过使用集算器可以将文本日志变成结构化数据,然后可以使用SQL式查询。集算器利用集算语言的优点,将日志内容结构化为数据表结构,SPL支持直接对结构化的文件进行SQL查询,不再需要安装配置第三方数据库软件。本文还详细介绍了具体的实施过程。 ... [详细]
  • 本文整理了Java面试中常见的问题及相关概念的解析,包括HashMap中为什么重写equals还要重写hashcode、map的分类和常见情况、final关键字的用法、Synchronized和lock的区别、volatile的介绍、Syncronized锁的作用、构造函数和构造函数重载的概念、方法覆盖和方法重载的区别、反射获取和设置对象私有字段的值的方法、通过反射创建对象的方式以及内部类的详解。 ... [详细]
  • 本文介绍了如何使用PHP向系统日历中添加事件的方法,通过使用PHP技术可以实现自动添加事件的功能,从而实现全局通知系统和迅速记录工具的自动化。同时还提到了系统exchange自带的日历具有同步感的特点,以及使用web技术实现自动添加事件的优势。 ... [详细]
  • 一、Hadoop来历Hadoop的思想来源于Google在做搜索引擎的时候出现一个很大的问题就是这么多网页我如何才能以最快的速度来搜索到,由于这个问题Google发明 ... [详细]
  • VScode格式化文档换行或不换行的设置方法
    本文介绍了在VScode中设置格式化文档换行或不换行的方法,包括使用插件和修改settings.json文件的内容。详细步骤为:找到settings.json文件,将其中的代码替换为指定的代码。 ... [详细]
  • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • 本文介绍了Redis的基础数据结构string的应用场景,并以面试的形式进行问答讲解,帮助读者更好地理解和应用Redis。同时,描述了一位面试者的心理状态和面试官的行为。 ... [详细]
  • 本文介绍了基于c语言的mcs51单片机定时器计数器的应用教程,包括定时器的设置和计数方法,以及中断函数的使用。同时介绍了定时器应用的举例,包括定时器中断函数的编写和频率值的计算方法。主函数中设置了T0模式和T1计数的初值,并开启了T0和T1的中断,最后启动了CPU中断。 ... [详细]
  • C# 7.0 新特性:基于Tuple的“多”返回值方法
    本文介绍了C# 7.0中基于Tuple的“多”返回值方法的使用。通过对C# 6.0及更早版本的做法进行回顾,提出了问题:如何使一个方法可返回多个返回值。然后详细介绍了C# 7.0中使用Tuple的写法,并给出了示例代码。最后,总结了该新特性的优点。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 本文介绍了游标的使用方法,并以一个水果供应商数据库为例进行了说明。首先创建了一个名为fruits的表,包含了水果的id、供应商id、名称和价格等字段。然后使用游标查询了水果的名称和价格,并将结果输出。最后对游标进行了关闭操作。通过本文可以了解到游标在数据库操作中的应用。 ... [详细]
author-avatar
qiutuiq
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有