在上一篇文章中,我们讨论了在文档型数据库中采用「关系视角」和「查询视角」进行数据建模的优缺点。文章的用例中,我们直接通过 “业务术语模型(Business Terms Model,BTM)” 给出了在关系型数据库及文档型数据库下“物理数据模型(Physical Data Model,PDM)”的不同实现「关系视角」及「查询视角」,直接对比了两种设计视角的优劣。
本文将继续使用相同的案例,探讨文档型数据库中的数据建模「设计原则」。首先,我们必须明确,在文档型数据库中并非只能采用「查询视角」进行建模。在文档型数据库中,我们可以通过「嵌入」以及「引用」实现数据间结构的呈现,为程序开发需求提供合适的支持。
「查询视角」的物理数据模型PDM

「关系视角」的物理数据模型PDM

通过对比在不同的视角下,我们可以看到,主要的区别在于 “订单” 数据的存放方式。在「查询视角」下,“订单”会包含其“订单明细”信息,所有数据放在统一个集合(表)中进行存放,订单的相关数据都「嵌入」都一起,获取数据时无需进行$lookup(JSON)操作。而在「关系视角」下,“订单”和“订单明细”会分别存放于两个集合(表)中,订单不同类型的数据存放在不同的集合(表)中,如果需要同时获得这些数据,需要跨集合(表)进行「引用」。
嵌入 vs 引用的设计原则
文档型数据库基于JSON灵活的数据结构,通过「嵌入」的数据组织方式对于数据查询展现更加友好,在实际开发中也更贴近OOP面向对象的编程方法,往往会是对性能及使用便利性的优先选择。而「引用」同样可以应用于文档型数据库中,当数据之间普遍存在“多对多”关系,且数据量可能导致单个文档过大时,「引用」是更合适的选择。
在文档型数据库中,嵌入(Embedding)和引用(Referencing)是常用的设计策略。
嵌入:通常在一对一关系中使用,将相关信息保存在同一文档中。对于一对多,可以使用数组或字典进行嵌入。
引用:则通过在文档中使用标量值或引用数组表示关系,常用于多对多的实体关系中。
这两种选择在设计中都有各自的优劣,需要根据具体情况进行权衡。在确定应该使用嵌入(Embedding)还是引用(Referencing)的过程中,我们也应该参考BTM的描述,关注不同实体间“一对一”、“一对多”、“多对多”方面的关系。

图1:销售业务系统的业务术语模型BTM
选择「嵌入」还是「引用」的原则和指南
简单性:将信息保存在一起是否导致更简单的数据模型和代码?(例如:案例中最大的业务是客户查询订单信息,开发代码时可以避免在跨集合查询数据,代码逻辑更简单,不需要$lookup操作性能也更好)
如果是,选择「嵌入」。
放在一起:信息片段之间是否存在“具有”、“从属”、“包含”或类似的关系?(例如:案例中逻辑上订单显然是包含其明细信息的,这也更符合人对业务的理解)
如果是,选择「嵌入」。
查询原子性:应用程序是否会一起查询这些信息片段?(例如:案例中每次订单查询,必然会一同展示订单明细)
如果是,选择「嵌入」。
更新复杂性:这些信息片段是否一起更新?(例如:案例中订单的总价,和订单明细的单价及产品数量有严格的对应,调整时必须一同调整)
如果是,选择「嵌入」。
归档:这些信息片段是否应该同时存档?(例如:作为历史的售卖记录,归档时订单和明细应该一同进行存档)
如果是,选择「嵌入」。
基数:关系的“多方”是否存在高基数?(数据基本不重复或者均为唯一值,例如:产品作为一对多或多对多的“多方”,相对于订单本身,就是高基数的体现)
如果不是,选择「引用」。
数据重复:嵌入是否会导致数据重复,而导致过于复杂以至于无法管理和不被接受?(例如:商品的描述信息,对订单本身没有直接意义,如果每个文档都保存商品描述,就会显得重复也浪费存储空间)
如果不是,选择「引用」。
文档大小:这些信息片段的组合大小是否会占用应用程序过多的内存或传输带宽?(例如:如果以上实例中还包括有对产品的评价信息,那么评价信息倾向于用引用进行处理,因为他们可能有很多,而且并非每次都要全部获取)
如果不是,选择「引用」。
文档增长:嵌入的片段是否会无限增长?(例如:订单、产品、产品的评价信息,实际上是无限增长的)
如果不是,选择「引用」。
10. 工作负载:在写密集型工作负载中,这些信息片段是否在不同时间写入?(例如:产品、客户都会有单独独立的工作负载对这部分做单独的处理)
如果是,选择「引用」。
11. 个性化:对于关系的子方面,片段是否可以在没有父方存在的情况下自行存在?(例如:订单、产品、客户在业务上都是单独的个体)
如果是,选择「引用」。
总结
文档型数据库建模设计,直接影响着系统的性能和可维护性。选择合适的数据库类型、合理设计数据模型,并在「嵌入」与「引用」之间做出明智的选择,都是确保数据库成功运行的关键步骤。通过本文介绍的方法和指南,设计人员能够更好地理解在文档型数据库建模设计的关键考虑因素,为项目的成功实施提供坚实基础。




