MongoDB 初窥
这周开始由于项目的原因正式接触 MongoDB,之前稍微看过一点,但没怎么正式用过,一方面是设计思维牢固的钉死在了关系数据库的三大范式上(第四和 BC 有点过了……),另一方面是没有一个机会去做 PHP 以外的站(嗯,因为黄金搭档……)。
所以兜兜转转,稍微介绍一下 MongoDB 的一些事。
引言
MongoDB 是一个 NoSQL (Not Only SQL) 的数据库,提供面向文档的存储,操作简单,天生的分布式,带文件存储功能(GridFS)。
基本上,我们可以把 MySQL 的概念无缝的迁移至 MongoDB:
database | database | 数据库 |
---|---|---|
table | collection | 数据库表/集合 |
row | document | 数据记录行/文档 |
column | field | 数据库字段/域 |
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 无感