Mongodb架构设计
参考链接:learnmongodbthehardway.com/schema/sche…
概览
Mongodb是文档型数据库,由于其不属于关系型数据库,不必遵守三大范式,而且也没有Join关键字来支持表连接,所以Mongodb的表结构设计跟Oracle、MySQL很不一样。下面针对几种不同的表设计结构分别举例:
1对1关系模型
在关系型数据库中,1对1关系模型通常是通过外键的形式进行处理。我们以作家跟地址来举例,假设这两个实体的关系是1对1,那么我们可能会像下面这样子建表
但是,为了方便,其实我们在设计表的时候不会严格遵守三大范式,会做一定的冗余数据,实际情况下可能就是这样子的表
那么,我们回到Mongodb,在这张非关系型的NoSQL数据库里,没有标准的外键(虽然我们可以手工建立连接,但是这种表之间的字段关联关系只能存在程序级别,数据库本身并没有提出外键约束的概念),我们可以怎么来建立表并处理表之间的关系呢?
- 建立连接
这种方式可以理解为建立外键,在其中一个表里建立对方的id字段
1 | 复制代码 用户信息的文档设计 |
- 内嵌文档
直接把地址信息的文档作为用户信息文档的一个字段储存进去
1 | 复制代码 { |
直接内嵌文档的好处就是我们可以在单次读操作就可以特定用户的用户信息文档以及对应的地址信息文档,当然了,这是在用户信息和地址信息强关联的时候,这样子直接内嵌才显得有意义。
1 | 复制代码 官方文档推荐1对1的数据模型尽量使用内嵌的方式,这样子会提高读操作的效率,更快地获取文档信息 |
1对多关系模型
1对多的关系模型,我们可以简单地以博客和对应的评论信息来举例
对应的Mongodb的表模型如下
1 | 复制代码博客信息的文档设计 |
在关系型数据库里,我们通常是分别建立两张表:一个Blog表、一个Comments表(从表,带有blog_id外键),然后通过join操作把两个表关联起来
但是在Mongodb里由于没有Join关键字,但是我们可以根据Mongodb的特点,得出以下三个解决方式:
- 内嵌
1 | 复制代码 内嵌了评论信息的博客文档设计 |
上面这种表设计的好处是,我们可以直接获取指定博客下的评论信息,用户新增评论的话,直接在blog文档下的comments数组字段插入一个新值即可。
但是这种表设计至少有三个如下的潜在问题需要注意:
1. 博客下的评论数组可能会逐渐扩增,甚至于超过了文档的最大限制长度:16MB
2. 第二个问题是跟写性能相关,由于评论是不停地添加至博客文档里,当有新的博客文档插入集合的时候,MongoDB会变得比较困难定位到原来的博客文档位置,另外,数据库还需要额外开辟新的内存空间并复制原来的博客文档、更新所有索引,这需要更多的IO交互,可能会影响写性能
1 | 复制代码 必须注意的是,只有高写入流量的情况下才可能会影响写性能,而对于写入流量较小的程序反而没有那么大的影响。视具体情况而定。 |
- 连接
第二个方式是通过建立类似外键的id来进行文档间的关联
1 | 复制代码 博客的文档设计 |
1 | 复制代码这样子设计模型有个好处是当评论信息逐渐增长的时候并不会影响原始的博客文档,从而避免了单个文档超过16MB的情况出现。而且这样子设计也比较容易返回分页评论。但是坏处的话,就是假设我们在一个博客文档下拥有非常多的评论时(比如1000条),那我们获取所有评论的时候会引起数据库很多的读操作 |
- 分块
第三个方法就是前面两种方法的混合,理论上,尝试去平衡内嵌策略和连接模式,举个例子,我们可能会根据实际情况,把所有的评论切分成最多50条评论的分块
1 | 复制代码 博客的文档设计 |
这样子设计最大的好处是我们可以单次读操作里一次性抓出50条评论,方便我们进行评论分页
1 | 复制代码 什么时候使用分块策略? |
多对多关系模型
多对多关系模型,我们以作者跟创作的书籍来举例
在关系型数据库里,我们可以通过中间表的方式来处理
- 双向嵌套
在MongoDB里我们可以通过双向嵌套,把两个文档的外键通过数组字段添加到彼此的文档里
1 | 复制代码 作者信息的文档设计 |
1 | 复制代码当我们进行查询的时候,可以通过两个维度互相进行查询 |
- 单向嵌套
单向嵌套策略是用来优化多对多关系模型里的读性能,通过将双向引用转移为类似一对多的单向引用。这种策略是有特定场景的,比如在我们这个案例中,我们设计的作者信息文档里,将书籍信息作为数组字段嵌入作者文档,但是实际情况下,书籍的数量是会快速地增长,很可能会突破单个文档16MB的限制。
在这个案例中,我们可以看到书籍数量是快速增长的,但是书籍分类确实比较固定,通常不会有太大改动,所以我们把书籍分类信息单独设计成文档,然后作者信息作为书籍信息的嵌入数组引用,书籍分类也作为嵌入数组引用。以相对变化不大的书籍分类作为主表,把相对变化较大的书籍信息作为从表,储存主表id作为外键。
1 | 复制代码 书籍分类的文档设计 |
相对应的查询语句如下
1 | 复制代码 通过指定书籍来查找对应的书籍分类 |
1 | 复制代码 根据指定书籍分类来查找对应书籍 |
本文转载自: 掘金