如何在Azure Cosmos DB中构建关系



我在cosmos中的同一个集合中有两组数据,一组是"posts",另一组为"users",它们由用户创建的posts链接。

目前我的结构如下;

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

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

我还担心性能,如果一个用户有10000个帖子,那就是10000个查找,我必须解决所有帖子。。

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

正如David所说,这是一个漫长的讨论,但它是一个非常常见的讨论,所以,由于我有一个小时左右的"空闲"时间,我非常高兴尝试回答它,希望能一劳永逸。

为什么要正常化

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

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

https://docs.mongodb.com/manual/core/data-model-design/#normalized-数据模型

但你真的需要它吗?既然您已经选择使用JSON文档数据库,那么您应该利用这样一个事实,即它能够存储整个文档,然后只将文档与所有所有者数据一起存储:姓名、姓氏或创建文档的用户的所有其他数据。是的,我的意思是,你可能想评估的不是帖子和用户,而是帖子,里面有用户信息。这实际上可能非常正确,因为你一定会在帖子创建时获得用户的准确数据。举个例子,我创建了一个帖子,我有传记"X"。然后我将我的传记更新为"Y",并创建一个新的帖子。这两篇文章将有不同的作者传记,这是恰到好处的,因为它们准确地捕捉到了现实。

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

如果所有的作者,为了在你的系统中存在,必须发布博客文章,这可能就足够了。但也许你想让一位作家写传记并在你的系统中列出,甚至在他写博客之前。

在这种情况下,您需要对模型进行NORMALIZE并创建一个新的文档类型,仅针对作者。如果是这种情况,那么,您还需要弄清楚如何处理前面描述的情况。当作者更新自己的传记时,你会只是更新作者文档,还是创建一个新的文档?如果你创建了一个新的帖子,这样你就可以跟踪所有的更改,你会不会也更新所有以前的帖子,让它们引用新的文档?

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

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

一致性

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

性能

性能可能是一个问题,但您通常不会首先为支持性能而建模。您建模是为了确保您的模型能够表示和存储您需要的真实世界中的信息,然后您对其进行优化,以使您选择使用的数据库具有良好的性能。由于不同的数据库将具有不同的约束,因此模型将进行调整以处理这些约束。这与过去关于"逻辑"与"物理"建模的讨论不谋而合。

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

不幸的是,分区是您一劳永逸的选择,所以您真的需要在脑海中清楚地知道您想要支持的最常见的用例是什么。如果您的大多数查询都是按作者进行的,我会按作者进行分区。

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

我真的希望这能帮助你开始找出答案。我真的希望这有助于促进和发展一场讨论(如何为文档数据库建模),我认为这场讨论现在已经成熟了。

最新更新