范式化和反范式化

范式化是将数据分散到多个不同的集合,不同集合之间可以相互引用数据。反范式化是将每个文档所需的数据都嵌入在文本内部。范式化能够提高数据写入速度,反范式化能够提高数据读取速度。

内嵌数据与引用数据的比较

更适合内嵌 更适合引用
子文档较小 子文档较大
数据不定期改变 数据经常改变
最终数据一致即可 中间阶段的数据必须一致
文档数据小幅增加 文档数据大幅增加
数据通常需要执行两次查询才能获得 数据通常不包含在结果中
快速读取 快速写入

基数

一个集合中包含的对其他集合的引用数量叫做基数。常见的关系有一对一、一对多、多对多。在 MongoDB 中,只要确定了多少的关系,就很容易在内嵌文档和引用数据之间进行数据之间进行权衡。通常来说,“少”的关系使用内嵌的方式会比较好,“多”的关系使用引用的方式比较好。

社交应用相关

对于人、好友、粉丝、内容以及一些其它的事物。对于这些高度联系的数据使用内嵌还是引用的形式不容易权衡。对于粉丝这种经常变换的内容进行范式化,将这些信息单独放在一张表中。对于一些有名的用户,粉丝数比较多,可以采用“连续的”文档。对粉丝文档进行拆分。

优化数据操作

要优化应用程序,首先要知道对读写性能进行评估以找到性能瓶颈。对读取操作的优化包括正确使用索引,以及尽可能将所需信息放在单个文档中返回。对写入操作的优化包括减少索引数量以及尽可能提高更新效率。经常需要在读取和写入效率之间进行权衡,选择一个更好的优化方案。

优化文档增长

更新文件时,明确更新是否会导致文件增长,以及增长速度。如果它的填充因子大于 1.2 ,可以考虑手动填充,在创建文档时创建一个更大的字段,文档创建成功后将这个字段删除。这样文档就分配了足够的空间供后续使用。这样做可以避免更新文档时发生文件移动。

删除旧数据

有三种常见的方式用于删除旧数据:使用固定集合,使用 TTL 集合,或者定期删除集合。

最简单的方法是使用固定集合:将集合大小设为一个比较大的值,当集合被填充时,将旧数据从固定集合中挤出。在密集插入数据时会大大降低数据在固定集合内的存活期。

TTL 集合可以精确控制删除文档的时机。但是,对于写入大量的集合来说这种方式不够快。它通过遍历 TTL 索引来删除文档。

不适合 MongoDB 的场景

  • MongoDB 不支持事务,对事务有要求的应用程序不建议使用 MongoDB。

  • 在多个不同维度上对不同类型的数据进行连接,这是关系型数据库擅长的,MongoDB 不支持这么做。

参考

[1] MongoDB权威指南