聊聊 MongoDB 数据库的设计
自从正式使用了 MongoDB 之后,不止一次吐槽过 MongoDB 的各种垃圾设定,包括但不仅限于:
- 没有事务
- 没有表连接(新版支持了,但估摸着性能堪忧)
也就是说,同样的操作,在 SQL 下通过 JOIN 控制原子性的,通过 MongoDB 可能就不得不去查个两次,而且原子性不可保证——MongoDB 官方也是非常实诚,人家在选型的时候就说了,如果贵系统对并发性(Concurrency)有强要求,那么 MongoDB 可能就不是你的菜了。
在 MongoDB 初窥 中我们也简单的介绍了锁机制,如有需要可以阅读。
前两天无聊接着看《MongoDB 权威指南》的时候看到一些观点,觉得给 MongoDB 数据库的设计起到了一定指导和参考作用,故作此文(笔记):
首先我们了解两个概念:
- 范式化:将数据分散到不同的集合,多个集合之间可以相互引用,这样要修改这部分数据,只要修改这部分数据所在的文档,其他区域与数据内容无关。
- 反范式化:每个文档所需的数据都存储在文档内部,每个文档都拥有自己的数据副本。如果要修改这部分数据,需要修改这块数据对应的每一个文档。
对于我们前文所说的,由于没有「连接」,范式化意味着我们要取出完整所需的数据可能要进行多次查询,而反范式化则只要一次查询即可。从写入的角度,我们可以看到,范式化写入的消耗更少,配合锁机制,对于拥有 subdocument
概念的 MongoDB,我们需要根据自己的实际需求去权衡。
在 SQL 中,我们经常会提起:一对一,一对多,多对多,而在 MongoDB 这样的数据库中,我们可以分为新的类型:少和多,之后我们会根据少和多进行一些数据库设计的详细分析,先来简单根据之前的介绍引用一下《MongoDB 权威指南》中的表格:
更适合内嵌 | 更适合引用 |
---|---|
子文档较小 | 子文档较大 |
数据不会定期改变 | 数据经常改变 |
最终数据一致即可 | 中间阶段的数据必须一致 |
文档数据小幅增加 | 文档数据大幅增加 |
数据通常需要执行二次查询才能获得 | 数据通常不包含在结果中 |
快速读取 | 快速写入 |
通常来说,「少」的关系对于内嵌更为合适,「多」则对于引用更加合适:比如文章和标签的关系可能是多对少,文章和评论的关系可能是一(少)对多。
所以我们的 Tags 可以内嵌,而评论则使用引用更好。
由于 MongoDB 的文档会自动扩充大小,如果太过频繁的让 MongoDB 产生文档移动,将会造成性能问题,在设计阶段,可以预留足够的空间,提高写入速度。
根据这一设计原理,结合 MongoDB 的一些限制,可以在一定程度上解决以下问题,而不是看心情靠玄学去进行设计:
- 我该不该用 MongoDB?
- 我该用引用还是 SubDocument?
植入部分
如果您觉得文章不错,可以通过赞助支持我。
如果您不希望打赏,也可以通过关闭广告屏蔽插件的形式帮助网站运作。
NoSQL一时爽 复杂逻辑毁一生啊
我也感觉 NoSQL 实际上并不适合复杂的场景,毕竟虽然说「非关系」,但是实际上关系是不可避免的,在设计时即使可能是同一个实体内的东西,为了优化也会抽离出去,以引用的形式去使用。这种时候一旦对「并发」、「事务」存在要求,马上就会 GG 了,因此我认为 NoSQL 还是需要提供一些简单的事务处理手段,以备不时之需。
讲完了?
这还不够?
这篇文章的内容很直白、很明确!是时候考虑是否将mongo换成mysql了...(哭)