认识NoSQL建模
用语 | 解释 |
---|---|
SoR | 记录系统(System of record)。泛指一等数据源(,应用的状态会以该数据源为准)。 |
派生数据库 | 根据 SoR 派生出来的(二等)数据源。通常用于满足 提高操作性能、扩展SoR特性 场景。 |
查询模式 | 特定于上下文的查询需求。 |
数据建模是指为数据设计内存结构和存储结构之间的映射关系的过程。而数据模型则是该过程的产物,它由一系列结构定义、约束规则及其关系组成。 Martin Fowler将数据模型定义为认知和操作数据时所使用的模型,是一种数据库组织数据的方式。
与SQL(泛指关系型数据库)不同。NoSQL 通常并不遵循关系建模范式。甚至不同的 NoSQL 实现其数据建模方式也大有差别。设计者需要根据 NoSQL 所提供的具体特性,以及系统实际的查询模式来进行建模决策。
关系模型的优势在于查询的灵活性和数据一致性。对于遵循范式的数据模型而言,可以通过灵活的 SQL 来聚合数据(如join)。而且因为没有冗余,所以其数据一致性几乎能够满足所有严苛场景。然而,在面对大数据量存取需求时,该模型会显得相当乏力。或者说,关系模型本身就不是针对大数据场景而设计的。
在为业务系统进行 NoSQL 数据建模时,比较常用的方案是面向聚合建模。简单来说就是将相关信息放在一起。至于“相关”到底如何定义,则取决于具体系统的查询模式。这是因为 NoSQL(通常)不提供ACID事务承诺,在多指令任务上下文中无法确保最基本的原子性。或者说,NoSQL 对于原子性的支持非常有限。大部分仅支持单指令/文档级别的原子性,所以在进行数据建模时就需要将相关信息放在一起,以便满足原子性。 面向聚合建模可以透过两种方式来实现:嵌入和引用。 嵌入指的是将关联(或其中的一部份)直接嵌入到主体(文档)中。适用于 数据规模较少、对读性能有要求、不可变 等需要场景。例如在电商上下文中,可以直接将订单项(列表)嵌入到具体订单中。以此来确保订单在提交后,其订单项(列表)不会被改变。 而引用的概念其实和关系模型中的外键大致相同。即只将关联的标识嵌入到主体(文档)中。适用于 数据量较大、对一致性有较高要求 等场景。 然而,因为聚合模型没有完全遵循范式设计,所以通常情况下多多少少都会存在一些冗余数据1。这使得设计者需要额外引入数据同步机制来确保其一致性。
聚合模型相较于关系模型需要更加关注具体系统的查询模式。因为关系模型本身查询起来比较灵活,所以建模时可以脱离系统查询模式而仅需遵循范式来进行设计。但聚合模型就不能这样。它需要根据具体 NoSQL 提供的特性,以及实际的查询模式来进行建模。
值得注意,现今大部分系统都会同时使用多种数据库2。但据经验而言,很多开发者会因为缺乏设计经验而忽略数据建模工作。他们往往会直接将 SoR 中的数据模型映射到派生数据库上。然而,这么做无疑会丧失派生数据库相关特性的优势。因为大部分派数据库都是 NoSQL,而它们需要根据自身提供的特性来进行数据建模才能发挥所长。