写点什么

为什么 MySQL 使用 B+ 树 (三)

  • 2019-12-26
  • 本文字数:2143 字

    阅读完需:约 7 分钟

为什么 MySQL 使用 B+ 树 (三)

作者使用 macOS 系统的页大小就是 4KB,当然在不同的计算机上得到不同的结果是完全有可能的。


当我们需要在数据库中查询数据时,CPU 会发现当前数据位于磁盘而不是内存中,这时就会触发 I/O 操作将数据加载到内存中进行访问,数据的加载都是以页的维度进行加载的,然而将数据从磁盘读取到内存中所需要的成本是非常大的,普通磁盘(非 SSD)加载数据需要经过队列、寻道、旋转以及传输的这些过程,大概要花费 10ms 左右的时间。



我们在估算 MySQL 的查询时就可以使用 10ms 这个数量级对随机 I/O 占用的时间进行估算,这里想要说的是随机 I/O 对于 MySQL 的查询性能影响会非常大,而顺序读取磁盘中的数据时速度可以达到 40MB/s,这两者的性能差距有几个数量级,由此我们也应该尽量减少随机 I/O 的次数,这样才能提高性能。


B 树与 B+ 树的最大区别就是,B 树可以在非叶结点中存储数据,但是 B+ 树的所有数据其实都存储在叶子节点中,当一个表底层的数据结构是 B 树时,假设我们需要访问所有『大于 4,并且小于 9 的数据』:



如果不考虑任何优化,在上面的简单 B 树中我们需要进行 4 次磁盘的随机 I/O 才能找到所有满足条件的数据行:


  1. 加载根节点所在的页,发现根节点的第一个元素是 6,大于 4;

  2. 通过根节点的指针加载左子节点所在的页,遍历页面中的数据,找到 5;

  3. 重新加载根节点所在的页,发现根节点不包含第二个元素;

  4. 通过根节点的指针加载右子节点所在的页,遍历页面中的数据,找到 7 和 8;


当然我们可以通过各种方式来对上述的过程进行优化,不过 B 树能做的优化 B+ 树基本都可以,所以我们不需要考虑优化 B 树而带来的收益,直接来看看什么样的优化 B+ 树可以做,而 B 树不行。


由于所有的节点都可能包含目标数据,我们总是要从根节点向下遍历子树查找满足条件的数据行,这个特点带来了大量的随机 I/O,也是 B 树最大的性能问题。


B+ 树中就不存在这个问题了,因为所有的数据行都存储在叶节点中,而这些叶节点可以通过『指针』依次按顺序连接,当我们在如下所示的 B+ 树遍历数据时可以直接在多个子节点之间进行跳转,这样能够节省大量的磁盘 I/O 时间,也不需要在不同层级的节点之间对数据进行拼接和排序;通过一个 B+ 树最左侧的叶子节点,我们可以像链表一样遍历整个树中的全部数据,我们也可以引入双向链表保证倒序遍历时的性能。



有些读者可能会认为使用 B+ 树这种数据结构会增加树的高度从而增加整体的耗时,然而高度为 3 的 B+ 树就能够存储千万级别的数据,实践中 B+ 树的高度最多也就 4 或者 5,所以这并不是影响性能的根本问题。

总结

任何不考虑应用场景的设计都不是最好的设计,当我们明确的定义了使用 MySQL 时的常见查询需求并理解场景之后,再对不同的数据结构进行选择就成了理所当然的事情,当然 B+ 树可能无法对所有 OLTP 场景下的查询都有着较好的性能,但是它能够解决大多数的问题。


我们在这里重新回顾一下 MySQL 默认的存储引擎选择 B+ 树而不是哈希或者 B 树的原因:


  • 哈希虽然能够提供 O(1) 的单数据行操作性能,但是对于范围查询和排序却无法很好地支持,最终导致全表扫描;

  • B 树能够在非叶节点中存储数据,但是这也导致在查询连续数据时可能会带来更多的随机 I/O,而 B+ 树的所有叶节点可以通过指针相互连接,能够减少顺序遍历时产生的额外随机 I/O;


如果想要追求各方面的极致性能也不是没有可能,只是会带来更高的复杂度,我们可以为一张表同时建 B+ 树和哈希构成的存储结构,这样不同类型的查询就可以选择相对更快的数据结构,但是会导致更新和删除时需要操作多份数据。


从今天的角度来看,B+ 树可能不是 InnoDB 的最优选择,但是它一定是能够满足当时设计场景的需要,从 B+ 树作为数据库底层的存储结构到今天已经过了几十年的时间,我们不得不说优秀的工程设计确实有足够的生命力。而我们作为工程师,在选择数据库时也应该非常清楚地知道不同数据库适合的场景,因为软件工程中没有银弹。


到最后,我们还是来看一些比较开放的相关问题,有兴趣的读者可以仔细思考一下下面的问题:


  • 常用于分析的 OLAP 数据库一般会使用什么样的数据结构存储数据?为什么?

  • Redis 是如何对数据进行持久化存储的?常见的数据结构都有什么?


如果对文章中的内容有疑问或者想要了解更多软件工程上一些设计决策背后的原因,可以在博客下面留言,作者会及时回复本文相关的疑问并选择其中合适的主题作为后续的内容。

Reference

相关文章


本文转载自 Draveness 技术博客。


原文链接:https://draveness.me/whys-the-design-mysql-b-plus-tree


2019-12-26 17:261053

评论

发布
暂无评论
发现更多内容

Swarm节点系统开发|Swarm节点APP软件开发

Vchat挖矿软件开发|Vchat挖矿系统APP开发

并发王者课-铂金9:互通有无-Exchanger如何完成线程间的数据交换

MetaThoughts

Java 多线程 并发

统一缓存帝国 - 实战 Spring Cache

悟空聊架构

缓存 passjava 悟空聊架构 7月日更 Spring Cache

小马哥的Java项目训练营-毕业总结

姑射仙人

银行业智能运维的探索与实践

云智慧AIOps社区

银行数字化转型 智能运维

Redisson 分布式锁源码 06:公平锁排队加锁

程序员小航

Java redis 分布式锁 redisson

DolphinDB插件开发深度解析

DolphinDB

数据库 大数据 时序数据库 插件开发 DolphinDB

研发管理和项目管理有哪些痛点?

万事ONES

研发管理 ONES 项目管理工具

互联网公司的「敏捷开发」流程是怎么样的?每个职位的角色和分工是什么?

万事ONES

union 分页/group/join 复杂查询(.net core/framework)

Spook

sql ORM

如何利用极狐GitLab CI提高生产力?

极狐GitLab

ci

替换 Spring Cloud,使用基于 Cloud Native 的服务治理

火山引擎开发者社区

云原生 后端 Service Mesh 服务网格

HVC矿机系统开发|HVC矿机软件APP开发

我给我讲GIT,并成功把我得罪了

加百利

git 7月日更

Python 绑定:从 Python 调用 C 或 C++

华为云开发者联盟

c c++ Python 函数 Python 绑定

网安行业这几个熟悉又陌生的名词,啥帽子都清楚啦?

郑州埃文科技

在数据库中如何查询表的创建时间?

华为云开发者联盟

数据库 日志 视图 GaussDB(DWS) 查找对象

DGTT挖矿智能合约系统软件开发案例

萌宠大陆APP开发|萌宠大陆系统软件开发

多媒体技术(一)之图形图像

轻口味

android 音视频 计算机图形学 图形图像处理

打造中国数字军人 数军科技携黑科技亮相军博会

科技热闻

Go 学习笔记之 数组

架构精进之路

Go 语言 7月日更

如何用EasyRecovery 快速找回误删的截图

淋雨

EasyRecovery 文件恢复 硬盘数据恢复 固态硬盘数据恢复

计算机时间到底是怎么来的?程序员必看的时间知识!

Kaito

操作系统 计算机基础 时间 ntp

拖延背后的故事

卢卡多多

拖延症 7月日更

RTC为何这么火?

anyRTC开发者

音视频 WebRTC RTC 实时通讯

我还是没有忍住,于是乎我开通了lua语言学习专栏!

李阿柯

lua 专栏

TCP 的 Keepalive 和 HTTP 的 Keep-Alive 是一个东西吗?

小林coding

计算机网络 HTTP TCP/IP

百度交易中台之商品推广流程构建以及实现

百度Geek说

中台 软件架构 电商 交易

华为云薛浩:媒体业务进入全面云化时代,云原生成为必然选择

华为云开发者联盟

云原生 媒体 音视频 华为云

为什么 MySQL 使用 B+ 树 (三)_语言 & 开发_Draveness_InfoQ精选文章