MongoDB 为什么不用B+Tree?

主要是为弄清楚这个问题
MySQL 和 MongoDB 两种不同类型的数据库使用了相似却不同的数据结构,为什么 MySQL 选择使用 B+ 树而 MongoDB 使用 B 树呢?

概述

根据官方介绍MongoDB 是一个通用的、面向文档的分布式数据库;MongoDB 的架构与 MySQL 非常类似,它们底层都使用了可插拔的存储引擎以满足用户的不同需求,用户可以根据数据特征选择不同的存储引擎,最新版本的 MongoDB 使用了 WiredTiger 作为默认的存储引擎,作为 MongoDB 默认的存储引擎,WiredTiger 使用 B 树作为索引底层的数据结构,但是除了 B 树之外,它还支持 LSM 树作为可选的底层存储结构,LSM 树的全称是 Log-structured merge-tree,你可以在 MongoDB 中使用如下所示的命令创建一个基于 LSM 树的集合(Collection)

db.createCollection("posts",{storageEngine:{wiredTiger:{configString: "type=lsm"}}})
  • 场景:这是mongodb需要面对和解决的场景
  • 作为非关系型的数据库,MongoDB 对于遍历数据的需求没有关系型数据库那么强,它追求的是读写单个记录的性能
  • 大多数 OLTP 的数据库面对的都是读多写少的场景,B 树与 LSM 树在该场景下有更大的优势

非关系型

MongoDB 是非关系型的文档数据库,它完全抛弃了关系型数据库那一套体系之后,在设计和实现上就非常自由,它不再需要遵循 SQL 和关系型数据库的体系,可以更自由对特定场景进行优化,而在 MongoDB 假设的场景中遍历数据并不是常见的需求

  • MySQL中使用 B+ 树是因为 B+ 树只有叶子节点会存储数据,将树中的每一个叶节点通过指针连接起来就能实现顺序遍历,而遍历数据在关系型数据库中非常常见;

  • MongoDB 和 MySQL 在多个不同数据结构之间选择的最终目的就是减少查询需要的随机 IO 次数,MySQL 认为遍历数据的查询是常见的,所以它选择 B+ 树作为底层数据结构,而舍弃了通过非叶节点存储数据这一特性,但是 MongoDB 面对的问题就不太一样了:

  • MongoDB 使⽤B-树,数据存储在磁盘上,被设计⽤在 数据模型简单,性能要求⾼的场合。性能要求⾼,而B/B+树的区别有⼀点:
    B+树内节点不存储数据,所有data存储在叶子节点导致查询时间复杂度固定为 log(n)。⽽B-树查询时间复杂度不固定,与 key 在树中的位置有关,最好为O(1)尽可能少的磁盘 IO 是提⾼性能的有效⼿段。MongoDB 是聚合型数据库,⽽ B-树恰好 key 和 data 域聚合在⼀起;

  • 虽然遍历数据的查询是相对常见的,但是 MongoDB 认为查询单个数据记录远比遍历数据更加常见,由于 B 树的非叶结点也可以存储数据,所以查询一条数据所需要的平均随机 IO 次数会比 B+ 树少,使用 B 树的 MongoDB 在类似场景中的查询速度就会比 MySQL 快。这里并不是说 MongoDB 并不能对数据进行遍历,我们在 MongoDB 中也可以使用范围来查询一批满足对应条件的记录,只是需要的时间会比 MySQL 长一些。

  • 小结:因为针对的使用场景不同,MySQL的遍历场景比较多,MongoDB主要对一行文档读写性能支持高,b+树和b-树的区别在于数据存储的位置,为了减少随机IO的次数,所以MongoDB选择了B-树来作为存储数据结构

问题2:对于单条数据的读写,哈希不是更强势,为什么选择B-树?

  • hash的时间复杂度为O(1),但是遍历数据的复杂度就是O(n),如果使用 B+ 树,那么单条记录查询的复杂度是 O(log n),遍历数据的复杂度就是 O(log n) + X,这两种不同的数据结构一种提供了最好的单记录查询性能,一种提供了最好的遍历数据的性能,但是这都不能满足 MongoDB 面对的场景 ——单记录查询非常常见,但是对于遍历数据也需要有相对较好的性能支持,哈希这种性能表现较为极端的数据结构往往只能在简单、极端的场景下使用。

LSM 树

LSM 树是一个基于磁盘的数据结构,它设计的主要目的是为长期需要高频率写入操作的文件提供低成本的索引机制;无论是 B 树还是 B+树,向这些数据结构组成的索引文件中写入记录都需要执行的磁盘随机写,LSM 树的优化逻辑就是牺牲部分的读性能,将随机写转换成顺序写以优化数据的写入。

LSM的优势在于写入,其写入速度是B树的1.5~2.0倍,但是它的读取性能是B树的1/3,甚至1/6.

总结:

  • MySQL 使用 B+ 树是因为数据的遍历在关系型数据库中非常常见,它经常需要处理各个表之间的关系并通过范围查询一些数据;但是 MongoDB 作为面向文档的数据库,与数据之间的关系相比,它更看重以文档为中心的组织方式,所以选择了查询单个文档性能较好的 B 树,这个选择对遍历数据的查询也可以保证可以接受的时延;

  • LSM 树是一种专门用来优化写入的数据结构,它将随机写变成了顺序写显著地提高了写入性能,但是却牺牲了读的效率,这与大多数场景需要的特点是不匹配的,所以 MongoDB 最终还是选择读取性能更好的 B 树作为默认的数据结构(对于这种数据结构,在之前上课的笔记里有,后面会慢慢把架构课的笔记放上来,一起总结)

参考链接:
https://wenku.baidu.com/view/5d0982ed8aeb172ded630b1c59eef8c75fbf951f.html
https://blog.csdn.net/u013066244/article/details/114241352

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注