如何在 Azure Cosmos DB 中构建关系?

twe*_*ypi 4 azure azure-cosmosdb

我在 Cosmos 的同一个集合中有两组数据,一组是“帖子”,另一组是“用户”,它们由用户创建的帖子链接。

目前我的结构如下;

// user document
{
id: 123,
postIds: ['id1','id2']
}

// post document
{
id: 'id1',
ownerId: 123
}
{
id: 'id2',
ownerId: 123
}
Run Code Online (Sandbox Code Playgroud)

我对这个设置的主要问题是它的可替代性,代码必须强制链接,如果有错误数据将很容易丢失而没有明确的方法来恢复它。

我还担心性能,如果用户有 10,000 个帖子,即 10,000 次查找,我将不得不解决所有帖子。

这是建模实体关系的正确方法吗?

mau*_*idb 7

正如大卫所说,这是一个很长的讨论,但这是一个非常普遍的讨论,因为我有一个小时左右的“空闲”时间,我很高兴尝试回答它,一劳永逸,希望如此。

为什么要标准化?

我在您的帖子中注意到的第一件事:您正在寻找某种程度的参照完整性(https://en.wikipedia.org/wiki/Referential_integrity),这是将更大的对象分解为其组成部分时所需要的。也称为规范化。

虽然这通常在关系数据库中完成,但它现在在非关系数据库中也变得流行,因为它有助于避免数据重复,这通常会产生比它解决的问题更多的问题。

https://docs.mongodb.com/manual/core/data-model-design/#normalized-data-models

但是你真的需要吗?由于您选择使用 JSON 文档数据库,因此您应该利用这样一个事实,即它能够存储整个文档,然后只存储文档以及所有所有者数据:姓名、姓氏或您拥有的关于用户的所有其他数据谁创建了文档。是的,我是说您可能想要评估没有帖子和用户,而只是帖子,其中包含用户信息。这实际上可能非常正确,因为您一定会获得现有用户的准确数据在创建帖子的那一刻。比如说我创建了一个帖子,我有传记“X”。然后我将我的传记更新为“Y”并创建一个新帖子。这两篇文章将有不同的作者传记,这是正确的,因为它们完全捕捉到了现实。

当然,您可能还想在作者页面中显示传记。在这种情况下,您会遇到问题。你会用哪一种?应该是最后一张了。

如果所有作者为了存在于您的系统中,都必须发布博客文章,这可能就足够了。但是,也许您希望作者撰写其传记并在您的系统中列出,甚至在他撰写博客文章之前。

在这种情况下,您需要规范模型并创建一个新的文档类型,仅供作者使用。如果这是您的情况,那么您还需要弄清楚如何处理之前描述的情况。当作者更新自己的传记时,您是只更新作者文档,还是创建一个新文档?如果您创建一个新的,以便您可以跟踪所有更改,您是否也会更新所有以前的帖子,以便他们引用新文档?

正如您所看到的,答案很复杂,实际上取决于您想从现实世界中获取什么样的信息。

所以,首先,弄清楚你是否真的需要将帖子和用户分开。

一致性

假设您确实希望将帖子和用户保存在单独的文档中,因此您对模型进行了规范化。在这种情况下,请记住,Cosmos DB(但通常是 NoSQL)数据库不提供任何类型的本机支持来强制执行参照完整性,因此您几乎可以依靠自己。当然,索引可以提供帮助,因此您可能希望索引 ownerId 属性,以便在删除作者之前,例如,您可以有效地检查他/她所做的任何博客文章,否则将成为孤儿。另一种选择是手动创建并保持更新的另一个文档,对于每个作者,跟踪他/她所写的博客文章。使用这种方法,您只需查看此文档即可了解哪些博客文章属于作者。您可以尝试使用触发器自动更新此文档,请记住,当您在 NoSQL 数据库中标准化时,保持数据一致是您的责任。这与关系数据库完全相反,在关系数据库中,您的责任是在对数据进行反规范化时保持数据的一致性。

表演

性能可能是一个问题,但您通常不会首先建模以支持性能。您建模是为了确保您的模型可以表示和存储您需要的来自现实世界的信息,然后您对其进行优化,以便在您选择使用的数据库中获得不错的性能。由于不同的数据库将具有不同的约束,因此模型将被调整以处理这些约束。这只不过是古老的“逻辑”与“物理”建模讨论。

在 Cosmos DB 的情况下,您不应该有跨分区的查询,因为它们更昂贵。

不幸的是,分区是您一劳永逸地选择的东西,因此您确实需要在脑海中清楚地知道您最想支持的最常见用例是什么。如果您的大部分查询都是按作者完成的,我会按作者进行分区。

现在,虽然这似乎是一个聪明的选择,但只有当你有很多作者时才会这样做。例如,如果您只有一个分区,则所有数据和查询都将进入一个分区,这会极大地限制您的性能。请记住,事实上,Cosmos DB RU 在所有可用分区之间拆分:例如,对于 10.000 RU,您通常会获得 5 个分区,这意味着您的所有值都将分布在 5 个分区中。每个分区的上限为 2000 RU。如果您的所有查询都只使用一个分区,那么您真正的最大性能是 2000 而不是 10000 RU。

我真的希望这可以帮助您开始找出答案。我真的希望这有助于促进和发展我认为现在真正应该和成熟的讨论(如何为文档数据库建模)。