每个集合存储多个实体类型通常是好的。是否将实体类型存储到单个文档中需要更多考虑。
正如大卫所提到的 - 如何对数据进行建模有点主观。
在集合中存储多个实体类型
首先......让我们谈谈在一个集合中存储多个实体。DocumentDB 集合不是表。集合不强制执行模式;换句话说,您可以在同一个集合中存储具有不同模式的不同类型的文档。您只需向文档添加类型属性即可跟踪不同类型的实体。
您应该将集合视为执行查询和事务的分区和边界单元。因此,在同一个集合中存储不同实体类型的一个巨大好处是您可以通过 sprocs 直接获得事务支持。
在文档中存储多个实体类型
是否在单个文档中存储多个实体类型需要更多考虑。这通常被称为去规范化(通过在单个文档中嵌入数据来捕获数据之间的关系)和规范化(通过创建到其他文档的弱链接来捕获数据之间的关系)您的数据。
通常,反规范化可提供更好的读取性能。
应用程序可能需要发出更少的查询和更新来完成常见操作。
通常,在以下情况下使用非规范化数据模型:
- 实体之间有“<em>contains”关系
- 实体之间有一对多的关系
- 非规范化数据不经常更改
- 非规范化数据不会无限制地增长
- 非规范化数据是文档中数据的组成部分
非规范化数据模型的示例:
{
"Id": 1001,
"Type": "Company",
"Industry": "Software",
"Employees": [
{
"Id": 10011,
"Type": "Employee",
"Name": "John Doe"
},
{
"Id": 10012,
"Type": "Employee",
"Name": "Jane Doe"
}
]
}
通常规范化提供更好的写入性能。
提供比反规范化更大的灵活性
客户端应用程序必须发出后续查询来解析引用。换句话说,规范化的数据模型可能需要到服务器的往返次数更多。
通常,使用标准化数据模型:
- 当反规范化会导致数据重复但不会提供足够的读取性能优势来超过重复的影响时。
- 表示一对多关系
- 表示多对多关系。
- 相关数据变化频繁
标准化数据模型示例:
{
"Id": 1001,
"Type": "Company",
"Industry": "Software"
}
{
"Id": 10011,
"Type": "Employee",
"Name": "John Doe",
"CompanyId": 1001
}
{
"Id": 10012,
"Type": "Employee",
"Name": "Jane Doe",
"CompanyId": 1001
}
混合方法
在规范化和反规范化之间进行选择不一定是非黑即白的选择。我经常发现一个成功的设计模式是一种混合方法,在这种方法中,您可以选择规范化对象字段的部分集合,并对其他字段进行反规范化。
换句话说,您可以选择去规范化频繁读取的稳定(或不可变)属性以减少后续查询的需要,同时规范化频繁写入/变异的字段以减少扇出写入的需要。
混合方法的示例:
// Author documents:
[{
"id": 1,
"firstName": "Thomas",
"lastName": "Andersen",
"countOfBooks": 3,
"books": [1, 2, 3],
"images": [{
"thumbnail": "http://....png"
}, {
"profile": "http://....png"
}, {
"large": "http://....png"
}]
}, {
"id": 2,
"firstName": "William",
"lastName": "Wakefield",
"countOfBooks": 1,
"books": [1, 4, 5],
"images": [{
"thumbnail": "http://....png"
}]
}]
// Book documents:
[{
"id": 1,
"name": "DocumentDB 101",
"authors": [{
"id": 1,
"name": "Thomas Andersen",
"thumbnailUrl": "http://....png"
}, {
"id": 2,
"name": "William Wakefield",
"thumbnailUrl": "http://....png"
}]
}, {
"id": 2,
"name": "DocumentDB for RDBMS Users",
"authors": [{
"id": 1,
"name": "Thomas Andersen",
"thumbnailUrl": "http://....png"
}, ]
}]