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

问题描述 投票:0回答:1

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

目前我的结构如下;

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

// post document
{
id: 'id1',
ownerId: 123
}
{
id: 'id2',
ownerId: 123
}

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

我也关注性能,如果用户有10,000个帖子,我需要做10000次查询才能解决所有帖子。

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

azure azure-cosmosdb
1个回答
2
投票

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

为什么要正常化?

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

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

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

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

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

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

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

正如您所看到的,答案很复杂,而且真正取决于您希望从现实世界中捕获哪种信息。

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

一致性

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

表演

性能可能是一个问题,但您通常不会为了首先支持性能而进行建模。您进行建模以确保您的模型可以表示并存储您从现实世界中获得的信息,然后对其进行优化,以便使用您选择使用的数据库获得良好的性能。由于不同的数据库将具有不同的约束,因此该模型将适用于处理该约束。这仅仅是好的旧的“逻辑”与“物理”建模讨论。

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

不幸的是,分区是您一劳永逸地选择的,因此您需要清楚地了解您最想要支持的最常见用例。如果大多数查询都是基于每个作者完成的,我会按照作者进行分区。

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

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

© www.soinside.com 2019 - 2024. All rights reserved.