NOSQL反规范化数据模型

23

很多时候,我看到NOSQL数据库中的数据是被存储在非规范化的状态下。例如,考虑一个国际象棋比赛记录。它可能不仅包含参与国际象棋比赛的玩家ID,还包括玩家的名字和姓氏。我猜这样做是因为在NOSQL中无法进行连接操作,所以如果只是复制数据,则可以在一次调用中检索所有所需数据,而无需手动应用程序级别处理数据。

但是,我不理解的是,现在当您想要更新国际象棋选手的姓名时,您将不得不编写一个查询,该查询既要更新该选手参与的所有国际象棋比赛记录,又要更新该选手的个人记录。这似乎会造成巨大的性能开销,因为数据库将不得不搜索该选手参与的所有比赛,并更新每条记录。

像我的例子一样,数据通常存储在非规范化的状态下吗?

3个回答

22

你是正确的,在NoSQL数据库中数据通常以非规范化的形式存储。

更新的问题部分来源于“最终一致性”这个术语。

在你的例子中,当你更新玩家的名字(虽然不常见,但确实可能发生),你会发起一个后台作业来更新所有其他记录中的名字。是的,当更新正在进行时,你可能会检索到旧值,但最终数据将是一致的。由于我们这里并不是编写ATM软件,所以在性能/一致性之间做出权衡是可以接受的。

你可以在这里找到更多信息:http://www.allbuttonspressed.com/blog/django/2010/09/JOINs-via-denormalization-for-NoSQL-coders-Part-2-Materialized-views


2
有一种看法是,用户更改他/她的名称的次数非常罕见。但读取和更改板数据的次数是巨大的。因此,优化更加常见的情况比只发生极少数情况的情况更有意义。
另一个要注意的问题是,通过在板数据下保留该名称数据的副本,实际上增加了读取的性能开销。每次获取板数据时,您都需要再前进一步并获取所有用户数据(即使您真正想要的只是名字和姓氏)。
再次强调将名字和姓氏放在板数据上的原因可能是,在显示板数据的屏幕上,您经常还会显示用户的姓名。
出于这些原因,您可以避免在NoSQL数据库中有重复的数据。(虽然在SQL数据库中也可以做到,但请注意,您会受到责备)。在NoSQL世界中,复制是相当普遍并得到推广的。

1

我在过去7年中使用NoSQL(Firestore)工作了2个相当大的项目,其中我能够从头开始编写代码(两个项目都有约50k LoC,一个每天大约有15k活跃用户)。 我根本没有使用反规范化。这个概念从来没有吸引过我,而在Firestore中文档读取相当便宜。

回到你的例子来; 加载棋盘游戏的其他数据似乎比立即显示名称更重要。我会根据后台的用户ID加载名称,并在其周围放置一个简单的客户端memoize / cache,以防止一遍又一遍地获取同一用户文档。

为了解决性能问题,我使用了生成派生数据。我会在数据库文档“onWrite”上设置监听器,然后将一些计算出的数据存储在另一个派生文档中。当源更改时,这些文档会自动更新,因此不会使事情复杂化。在棋盘游戏的情况下,一个精简的文档可以是常常向应用程序所有用户展示的排行榜。

我需要进行的另一个优化是对最近打开的“项目”的标题+元数据长列表进行精简。Web客户端上的Firestore不提供在查询中选择文档字段的能力。它只获取完整的文档,这对于列表来说是太多的数据,因此我们通过制作API端点来获取精简数据来解决这个问题。

我并不是说你应该听从我的建议,但就代码复杂性和数据库成本而言,我们似乎做得很好。所以当我读到NoSQL需要数据去规范化时,我变得怀疑 :)

这是我的两分钱。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接