mongodb野史

最近因为新游戏业务的需要,打算抛弃mysql,拥抱mongodb,于是打算找mongodb本人聊聊,看看是否真的有值得被用的价值。

mongodb从办公区走了出来,高高瘦瘦的一个年轻小伙子啊,本以为应该是一个小肥仔呢,毕竟芒果不就是肥肥胖胖的吗。

image-20211010163332919

你好,请问你是芒果db吗?我率先打起了招呼。

mongodb回复,是呀,不过我不叫芒果db,我叫mongodb啦,我的原名取自英文单词"Humongous",寓意庞大,人如其名,意味着我是具备处理大规模数据能力的。

嗯,志存高远啊,不错,之前问过mysql阿姨,她说你和她不一样,她比较擅长处理关系型的数据,你比较理性,比较擅长处理非关系型的数据,还自称文档型数据库,想问问看你们两个的职责有什么区别吗?

image-20211010163502838

首先我先解释下什么是文档型数据库哈,文档是数据的基本单元,将多个键值对有序地放置在一起称为文档。可能这么说你也不大理解,这样吧,你看下这个表格就明白了

image-20211010163932109

简单的解释便是文档对应了数据库内的行。

至于职责上其实就和mysql阿姨描述的一样,我们一个是处理关系型,一个是处理非关系型,算是互补,对你们使用者来说,如果是因为业务需求或者是项目初始阶段,而导致数据的具体格式无法明确定义的话,使用mongodb最合适啦,相比关系型数据库来说,我们比较非常容易被扩展,这也为写代码带来了极大的方便。

哦,明白,那找你算是找对啦,我们游戏数据本身没什么关系,不过我们项目组这边和mysql阿姨比较熟悉,毕竟经常合作的,mongodb是第一次了解,想问问小哥哥,新手入门会不会比较困难呀?

看出来你们是新手了哈哈,放心啦,不会的,因为mysql阿姨的设计很优秀,并且使用广泛,因而我的爸爸Dwight Merriman在设计之初,也是严格参考了mysql的概念模型的,毕竟向前辈学习也是很重要的嘛,因而很多人都说,mongodb是 NoSQL中最像mysql的数据库的,你看看这个表格就知道啦

image-20211010122416995

基本上就是换了个叫法而已,至于有什么区别,我让他们本人出来和你解释吧。

mongodb说完,便跑出了几个小弟,原来mongodb还是一个小团队啊,刚刚和我聊的原来是队长,主要负责销售,各司其职,精妙啊。

image-20211010163551743

首先是名叫database数据库的小伙子开口了,他说他与mysql阿姨的数据库(database)概念相同,一个数据库包含多个集合(表),说完便笑嘻嘻的走开了。

接着是名叫collection集合的壮汉,哇,这身肌肉实在是绝了,他说他相当于mysql阿姨的表(table),一个集合可以存放多个文档(行),不过他的不同之处就在于集合的结构(schema)是动态的,不需要预先声明一个严格的表结构。

后面是名叫document 文档的小老妹和叫field字段小老弟开口,两个人都比较害羞,娇滴滴的说一个相当于SQL中的行(row),一个文档由多个字段(列)组成,并采用bson(json)格式表示,另一个相当于SQL中的列(column),相比普通column的差别在于field的类型可以更加灵活,比如支持嵌套的文档、数组。

filed字段小老弟说完,也给我画了一个表格,说是字段的对照。

image-20211010123907226

听完几个小伙子的发言,我感叹到,设计真精妙,对新手太友好了。不过刚刚听到了一个比较新的东西,bson是什么呢?

mongodb队长大叫了一声,bson出来下,说说你是个什么东西。

mongodb队长说完,在场的都笑了哈哈哈。

bson听到有人叫他,便跑了出来。

嗯,长得很帅气的一个小伙子。

image-20211010163648567

bson说,MongoDB 文档从格式上讲,是基于 JSON 的,典型的格式是这样的:

{
  "_id": 1,
  "name" : { "first" : "John", "last" : "Backus" },
  "contribs" : [ "Fortran", "ALGOL", "Backus-Naur Form", "FP" ],
  "awards" : [
    {
      "award" : "W.W. McDowell Award",
      "year" : 1967,
      "by" : "IEEE Computer Society"
    }, {
      "award" : "Draper Prize",
      "year" : 1993,
      "by" : "National Academy of Engineering"
    }
  ]
}
复制代码

曾经,JSON 的出现及流行让 Web 2.0 的数据传输变得非常简单,所以使用 JSON 语法是非常容易让开发者接受的。但是 JSON 也有自己的短板,比如无法支持像日期这样的特定数据类型,因此 MongoDB 实际上使用的是一种扩展式的JSON,叫 BSON(Binary JSON),可以支持多种结构类型,简言之,我就是JSON老哥的升级版,给你看看我支持的数据类型

image-20211010163948172

哦,了解了,刚刚听field字段小老弟说到_id,想了解下在分布式情况下,mongodb在唯一id这块怎么做到对抗高并发的?我们之前在调研mysql分布式应用的时候,发现mysql这块没做处理,还是挺蛋疼的。

field字段小老弟听到我在问他问题,于是就很害羞的走了出来,奶声奶气的说,基本上使用mysql等关系型数据库时,主键都是设置成自增的,不过在分布式环境下很容易冲突,为此我们采用了一个称之为ObjectId的类型来做主键,ObjectId是一个12字节的 BSON 类型字符串,每一个主键由4部分构成:

  • 4字节:UNIX时间戳
  • 3字节:表示运行MongoDB的机器
  • 2字节:表示生成此_id的进程
  • 3字节:由一个随机数开始的计数器生成的值

前三个部分可以保证在每一秒每一个mongo进程产生的文档id是不同的,然后每一个mongo进程会自己维护一个计数器,那么同一进程每一秒内的文档也会不同,但是会有一个上限值,跟计数器的位数有关。通过这种方式保证了在同一个集合中的唯一性。

嗯,确实,通过这四部分,基本可以说是唯一的了。

看我表现的比较满意,mongodb队长继续补充,在操作语法这块想必你也应该考虑过是否用起来比较丝滑的问题,放心,我们对数据的操作命令也基于JSON/BSON 格式,基本上没什么学习成本,给你举几个例子

比如插入文档的操作:

image-20211010153351527

执行文档查找:

image-20211010153404721

删除文档:

image-20211010153418791

在传统的SQL语法中,可以限定返回的字段,MongoDB可以使用Projection来表示:

image-20211010153431191

你应该也发现啦,这种基于BSON/JSON 的语法格式并不复杂,它的表达能力甚至要比SQL更加强大。

嗯,确实丝滑,我们项目组那边的小伙伴应该会很喜欢,突然想皮下,那如果我们想使用SQL语句进行查询什么的,可以嘛?

mongodb队长微微一笑,当然是可以的,不过需要借由第三方工具平台实现,你是服务端,可以看看 presto 之类的一些平台,如果是客户端的话,可以考虑使用mongobooster、studio3t 这样的工具。

对了,索引这块呢,在mysql中我们可是在这块折腾了许久,会不会换成mongodb,又得从头再来一次呢?

嘿嘿嘿,mongodb再次发出了笑声,仿佛是猜到了我想问什么一样,不用。

首先索引的技术实现依赖底层的存储引擎,目前我们使用 wiredTiger 作为默认的引擎。该引擎在在索引的实现上使用了 B+树的结构,这与其他的传统数据库并没有什么不同,这意味着大部分SQL数据库的一些索引调优技巧在 MongoDB 上仍然是可行的。

哇,这就太好啦,那怎么创建索引呢?

别急,看我给举几个例子,mongodb这边使用 ensureIndexes 为集合声明一个普通的索引

db.book.ensureIndex({author: 1})
复制代码

author后面的数字是啥意思呢? 1 代表升序,如果的话是降序则是 -1,这点应该是很好理解的。

那么如何实现复合式(compound)的索引呢?我们可以看看

db.book.ensureIndex({type: 1, published: 1})
复制代码

不过只有对于复合式索引时,索引键的顺序才变得有意义。

看吧,是不是很简单,基本上都是很清晰的。

除此之外,mongodb还支持以下几种索引:

  • 哈希(HASH)索引,哈希是另一种快速检索的数据结构,MongoDB 的 HASH 类型分片键会使用哈希索引。
  • 地理空间索引,用于支持快速的地理空间查询,如寻找附近1公里的商家。
  • 文本索引,用于支持快速的全文检索
  • 模糊索引(Wildcard Index),一种基于匹配规则的灵活式索引,在4.2版本开始引入。

这几种索引类型,貌似mysql也是没有的。

确实,地理空间索引这些貌似没听说过,当然了,也可能是我没用过,那么索引的特性也都有嘛?

那必须的啊,可以通过设置参数来赋予索引特性呀,比如

  • unique=true,表示一个唯一性索引
  • expireAfterSeconds=3600,表示这是一个TTL索引,并且数据将在1小时后老化
  • sparse=true,表示稀疏的索引,仅索引非空(non-null)字段的文档
  • partialFilterExpression: { rating: { $gt: 5 },条件式索引,即满足计算条件的文档才进行索引

挺好啊,基本一致,学习成本确实低啊,那是不是索引评估这块也是使用explain啊。

对头,可以使用 explain() 命令可以用于查询计划分析,进一步评估索引的效果,比如

image-20211010155541852

可以从结果看出执行计划是否高效,比如未能命中索引的结果,会显示COLLSCAN,命中索引的结果,使用IXSCAN,出现了内存排序,显示为 SORT,开发人员便可以通过结果进行调优啦。

啊啊啊,挺好挺好,对于我们这群mysql转mongodb的来说,基本没什么学习成本啊,另外,你给我推荐基本书吧,你推荐的,我们也比较放心。

没问题呀,诺,刚好我们这边也在收集相关资料

image-20211010161225895

还不错,有需要自取啦,点击链接

好啊,这样,你来我们项目组这边做个分享吧,我们小伙伴这边想听听高可用这块的设计呢。

好呀,我们晚点再约个时间,到时候再细聊。

关于mysql相关的,有兴趣的朋友也可以看看 zhuanlan.zhihu.com/p/404685504

这篇文章写的比较认真,有帮助的话,求各位朋友们点赞 + 喜欢 + 收藏支持下啦!❤️

我是稀饭下雪,持续分享编程干货,后面高可用这块等我和mongodb队长约好时间,我们不见不散。

猜你喜欢

转载自juejin.im/post/7018337724767666207