MongoDB 初窥

这周开始由于项目的原因正式接触 MongoDB,之前稍微看过一点,但没怎么正式用过,一方面是设计思维牢固的钉死在了关系数据库的三大范式上(第四和 BC 有点过了……),另一方面是没有一个机会去做 PHP 以外的站(嗯,因为黄金搭档……)。

所以兜兜转转,稍微介绍一下 MongoDB 的一些事。

引言

MongoDB 是一个 NoSQL (Not Only SQL) 的数据库,提供面向文档的存储,操作简单,天生的分布式,带文件存储功能(GridFS)。

基本上,我们可以把 MySQL 的概念无缝的迁移至 MongoDB:

databasedatabase数据库
tablecollection数据库表/集合
rowdocument数据记录行/文档
columnfield数据库字段/域

MongoDB 的基本元素是 document,也就是存入的 BSON 或者 JSON,最小元素是 field(这句话是我口胡的)。在一个 document 中可以嵌入 document 并且实现内部的查找(也可以看错 field 可以是一个 Object)。

文档关联

当然这篇不是说一个引言就结束了的(我也很想结束但是怕被打),所以我们再来多聊几个话题,这也是我一直以来比较烦恼的一个话题:没有 JOIN 怎么玩。

在 MongoDB 中有个 ObjectId 的概念,可以插入 ObjectId,查询两次,即可找到对应的值。

另一种方法是 $lookup,在 3.2 的版本中新加入的功能,引入了 foreignField 的概念(对,和 foreignKey 简直一毛一样),$lookup 相当于 MySQL 中的 LEFT JOIN。

详细的内容可见:https://docs.mongodb.com/manual/reference/operator/aggregation/lookup/

集合设计

另一个纠结的是,MongoDB 弱化了关系的概念,尤其在此之前都没有 JOIN,那么设计数据库的时候是不是应该换个想法,很明显我们可以省 SQL 设计中的一大堆连接表。(这次能学会纯属太久没设计数据库已经忘得差不多了)

之前似乎看过好几条 NoSQL 的设计原则,后来全忘了,只记得一条一个对象一个 collection……

这样子其实设计变得更加简单了(只要不把自己坑到就可以随便设计,毕竟无论嵌套多少 document 都是可查的),过去设计数据库的时候考虑第三范式甚至是画 ER 图完全没有必要。

当然,最好把频繁写的模块抽离出来,而不去设计太大的一个对象,之所以这样设计是因为频繁写会造成频繁锁死,从而使数据库的性能下降,这和我们之后讨论的锁有关。

在设计的时候,遇到了一个要存内容版本控制的问题,由于 MongoDB 天生不支持事务,导致我必须依赖他内部的锁机制。(尽管组长说无所谓但我还是……冷静了一下,想看看锁机制到底长啥样)。

在查资料的时候 MongoDB 大概的介绍还处于没有 JOIN 以及锁只有全局锁的阶段,所以看了一下最新版的文档:

MongoDB 提供了多级锁:全局、数据库和集合级别,允许存储引擎实现在集合级别之下的并发控制,MongoDB 根据不同的引擎也确实有不同的表现。

MongoDB 的锁有四种:X、IX、IS、S。X 写锁,也叫排他锁,S,读锁,也叫共享锁。这个在数据库书上都有,IS 和 IX 是一个之前没有的概念,intent exclusive 和 intent shared。可以考虑他们是相比 X 和 S 比较弱的锁。IS 和 IX 用于当被读写锁锁住时用于更粗粒度的锁定。IS 与 IX 可以共存,而 X 不能与任何其他锁共存,S 只能与 IS 共存。

为了优化吞吐量,MongoDB 会按照 FIFO(先来先服务)一次性把能共存的锁一起处理。

在 MongoDB 3.0 之后,MongoDB 开始使用 WiredTiger 引擎,它在全局、数据库、集合中只是用 intent locks。

当然,锁的粒度是一个问题,更重要的一个问题是,在MongoDB 中,他明确表示了只能保证单 document 的原子性,这意味着多 document 的操作可能会遇到一系列非原子操作的传统问题,为了保证原子性,我们就选择了把所有版本存在了同一个 document 中。

所以最终我们的设计变成了:

{
    _id: ObjectId("..."),
    data: [
        { vid: 1, content: "foo" },
        { vid: 2, content: "bar" }
    ]
}

参考资料

说了这么多,MongoDB 的坑主要还是出在锁机制上,这篇文章或许也可以叫做 MongoDB 锁初窥,基本上就是翻译了一下文档……因为英语太差万一理解错了请各位大佬指正。

植入部分

如果您觉得文章不错,可以通过赞助支持我。

如果您不希望打赏,也可以通过关闭广告屏蔽插件的形式帮助网站运作。

标签: 知识, 使用, mongodb

已有 2 条评论

  1. 花吹雪

    这篇好像确实讲的比较浅,不过还是棒棒哒!

    1. 是的 目前还对 MongoDB 无感

添加新评论