2025上半年,最新 AI实践都在这!20+ 应用案例,任听一场议题就值回票价 了解详情
写点什么

为什么 MongoDB 使用 B 树(二)

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

    阅读完需:约 5 分钟

为什么 MongoDB 使用 B 树(二)

非关系型

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



MySQL 中使用 B+ 树是因为 B+ 树只有叶节点会存储数据,将树中的每一个叶节点通过指针连接起来就能实现顺序遍历,而遍历数据在关系型数据库中非常常见,所以这么选择是完全没有问题的7


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



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


SQL


SELECT * FROM comments WHERE created_at > '2019-01-01'
复制代码


很多人看到遍历数据的查询想到的可能都是如上所示的范围查询,然而在关系型数据库中更常见的其实是如下所示的 SQL —— 查询外键或者某字段等于某一个值的全部记录:


SQL


SELECT * FROM comments WHERE post_id = 1
复制代码


上述查询其实并不是范围查询,它没有使用 >< 等表达式,但是它却会在 comments 表中查询一系列的记录,如果 comments 表上有索引 post_id,那么这个查询可能就会在索引中遍历相应索引,找到满足条件的 comment,这种查询也会受益于 MySQL B+ 树相互连接的叶节点,因为它能减少磁盘的随机 IO 次数。


MongoDB 作为非关系型的数据库,它从集合的设计上就使用了完全不同的方法,如果我们仍然使用传统的关系型数据库的表设计思路来思考 MongoDB 中集合的设计,写出类似如上所示的查询会带来相对比较差的性能:


JavaScript


db.comments.find( { post_id: 1 } )
复制代码


因为 B 树的所有节点都能存储数据,各个连续的节点之间没有很好的办法通过指针相连,所以上述查询在 B 树中性能会比 B+ 树差很多,但是这并不是一个 MongoDB 中推荐的设计方法,更合适的做法其实是使用嵌入文档,将 post 和属于它的所有 comments 都存储到一起:


JSON


{    "_id": "...",    "title": "为什么 MongoDB 使用 B 树",    "author": "draven",    "comments": [        {            "_id": "...",            "content": "你这写的不行"        },        {            "_id": "...",            "content": "一楼说的对"        }    ]}
复制代码


使用上述方式对数据进行存储时就不会遇到 db.comments.find( { post_id: 1 } ) 这样的查询了,我们只需要将 post 取出来就会获得相关的全部评论,这种区别于传统关系型数据库的设计方式是需要所有使用 MongoDB 的开发者重新思考的,这也是很多人使用 MongoDB 后却发现性能不如 MySQL 的最大原因 —— 使用的姿势不对。


有些读者到这里可能会有疑问了,既然 MongoDB 认为查询单个数据记录远比遍历数据的查询更加常见,那为什么不使用哈希作为底层的数据结构呢?



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


本文转载自 Draveness 技术博客。


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


2019-12-26 17:282175

评论

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

去你的35岁危机|ONES 人物

万事ONES

程序员 ONES

WebAssembly技术_在Web端运行C与C++程序(win10)

DS小龙哥

webassembly 3月月更

英特尔X钉钉:以智能协作驱动数字办公发展

科技新消息

校招项目应该如何准备才能高大上一点

宇宙之一粟

项目 3月月更

大数据,不只“懂数”,更要“懂行”

鼎道智联

大数据

元宇宙跟区块链的关系是什么呢?

CECBC

最终信息模式:终结香农极限,语义通信的另类空间

脑极体

面试官:你在项目中用过 多线程 吗?

田维常

面试 java面试

数字人民币为全球CBDC监管提供宝贵经验

CECBC

Linux之export命令

入门小站

在线Js,JavaScript压缩格式化工具

入门小站

工具

使用云服务器ECS搭建DoH服务的开发实践

阿里云弹性计算

征文投稿 玩转ECS DoH

我写的 Python 代码,同事都说好

AlwaysBeta

Python Pythonic

【Zeekr_Tech】TARA攻击树分析方法论

Zeekr_Tech

信息安全 极氪

配置Mountebank环境-mountebank系列(2)

Bruce Talk

技术 敏捷 Agile

电阻电路的等效变换(Ⅰ)

謓泽

3月月更

小程序加入智能家居行业,共创未来美好生活

發財KK

物联网 小程序容器 智慧生活 全屋智能 智能家居生态平台

3大能力升级,云效+钉钉,让研发协作更「敏捷」

阿里云云效

云计算 阿里云 云原生 钉钉 敏捷研发

java高级用法之:在JNA中将本地方法映射到JAVA代码中

程序那些事

Java Netty 程序那些事 3月月更

cdr2022新版本号V24.0.0301简体语言新增功能

茶色酒

cdr2022

Apache Flink 在国有大型银行智能运营场景下的应用

Apache Flink

大数据 flink 编程 流计算 实时计算

关注:车联网的数据安全问题

發財KK

车联网 物联网 数据安全 隐私安全 信息服务

我们如何建立一套无参考视频质量评价体系?

声网

视频 Dev for Dev VQA

5G区块链技术让建水紫陶有了“身份证”

CECBC

在线JSON转YAML工具

入门小站

工具

聊聊我对敏捷项目交付的理解

老张

交付质量 项目交付

OpenMLDB 在线模块架构解析

第四范式开发者社区

人工智能 机器学习 数据库 开源 特征平台

创业圈的哈利波特们注意了!霍格沃兹即将开学,谁是你的魔法导师?

创业邦

前Cisco思科首席工程师、Webex AV1第一人Thomas加入微帧科技!

微帧Visionular

视频编码

区块链的支付模式

CECBC

AI与开源的碰撞 昇思MindSpore TechDay直播来袭

极客天地

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