我在波斯菊的同一集合中有两组数据,一组是“帖子”,另一组是“用户”,它们由用户创建的帖子链接。
目前我的结构如下;
// user document
{
id: 123,
postIds: ['id1','id2']
}
// post document
{
id: 'id1',
ownerId: 123
}
{
id: 'id2',
ownerId: 123
}
此设置的主要问题是它的可替代性,代码必须强制执行链接,并且如果存在错误,很容易丢失数据,而没有明确的恢复方法。
我还担心性能,如果用户有10,000个帖子(即10,000个查询),我将不得不解决所有帖子。
这是建模实体关系的正确方法吗?
答案 0 :(得分:2)
正如大卫所说,这是一个漫长的讨论,但这是一个非常普遍的讨论,因此,由于我有大约一个小时的“空闲”时间,因此我很高兴尝试一次全部回答,希望如此。
为什么要标准化?
我在您的帖子中注意到的第一件事:您正在寻找某种程度的参照完整性(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属性建立索引,例如,在删除作者之前,您可以有效地检查他/她所做的任何博客文章是否将其保留为孤儿。 另一个选择是手动创建并保持更新的ANOTHER文档,该文档对于每个作者而言都跟踪他/她撰写的博客文章。使用这种方法,您只需查看本文档即可了解哪些博客帖子属于作者。您可以尝试使用触发器使此文档自动更新,或者在您的应用程序中进行更新。 请记住,当您在NoSQL数据库中进行标准化时,保持数据一致是您的责任。这与关系数据库正好相反,在关系数据库中,您的责任是在对数据进行非规范化时使其保持一致。
性能
性能可能是一个问题,但是通常您并不首先为了支持性能而建模。为了确保您的模型可以代表并存储现实世界中所需的信息,您可以进行建模,然后对其进行优化,以使您选择使用的数据库具有良好的性能。由于不同的数据库将具有不同的约束,因此该模型将适用于应对该约束。这与老式的“逻辑”与“物理”建模讨论一样多。
在Cosmos DB的情况下,您不应该使用跨分区查询,因为它们更昂贵。
不幸的是,分区是您一劳永逸地选择的东西,因此您确实需要清楚地了解最希望支持的最常见用例是什么。如果您的大部分查询都是按作者进行的,那么我将按作者进行分区。
现在,虽然这似乎是一个明智的选择,但只有当您有很多作者时,这才是明智的选择。例如,如果只有一个分区,则所有数据和查询将仅进入一个分区,从而极大地限制了您的性能。请记住,事实上,Cosmos DB RU被划分为所有可用分区:例如,使用10.000 RU,您通常会获得5个分区,这意味着所有值都将分布在5个分区中。每个分区的最高限制为2000 RU。如果所有查询仅使用一个分区,则实际的最大性能是2000而不是10000 RU。
我真的希望这能帮助您开始找出答案。我真的希望这有助于促进和发展我认为现在已经成熟的讨论(如何为文档数据库建模)。