在数据库中,何时应存储派生数据?

时间:2010-11-08 19:06:40

标签: mysql normalization

我的问题是关于非规范化。在数据库中,何时应将派生数据存储在自己的列中,而不是每次需要时都计算它?

例如,假设您的用户获得Upvotes的问题。您在其个人资料中显示用户的声誉。当用户被上调时,您应该增加他们的声誉,还是应该在检索他们的个人资料时计算它:

SELECT User.id, COUNT(*) AS reputation FROM User
LEFT JOIN Question
  ON Question.User_id = User.id
LEFT JOIN Upvote
  ON Upvote.Question_id = Question.id
GROUP BY User.id

在使用自己的列以增量方式跟踪用户的声誉之前,查询获取用户信誉的程度是多少?

继续我们的例子,假设一个Upvote的权重取决于投射它的用户有多少Upvotes(而不是多少声誉)。检索其声誉的查询突然爆炸:

SELECT
  User.id AS User_id,
  SUM(UpvoteWeight.weight) AS reputation
FROM User
LEFT JOIN Question
  ON User.id = Question.User_id
LEFT JOIN (
  SELECT
    Upvote.Question_id,
    COUNT(Upvote2.id)+1 AS weight
  FROM Upvote
  LEFT JOIN User
    ON Upvote.User_id = User.id
  LEFT JOIN Question
    ON User.id = Question.User_id
  LEFT JOIN Upvote AS Upvote2
    ON
      Question.id = Upvote2.Question_id
      AND Upvote2.date < Upvote.date
  GROUP BY Upvote.id
) AS UpvoteWeight ON Question.id = UpvoteWeight.Question_id
GROUP BY User.id

这与增量解决方案的难度远远不成比例。归一化何时值得,以及归一化的好处何时会失去非规范化的好处(在这种情况下是查询难度和/或性能)?

3 个答案:

答案 0 :(得分:4)

  

在使用自己的列以增量方式跟踪用户的声誉之前,查询获取用户信誉的程度是多少?

这里有两个问题,一个是幌子:(1)这种改变会改善性能吗?(2)性能提升是否值得付出努力?


就性能是否提高而言,这基本上是标准的利弊分析。

规范化的好处基本上是双重的:

  • 更轻松的数据完整性

  • 重新计算没有问题(例如,如果基础数据发生变化,则需要重新计算派生列)。

如果您使用强大的解决方案(例如触发器,Sstored-proc-only数据更改以及已撤销的直接表更改权限等)来覆盖数据完整性,那么这将成为验证成本是否直接计算源数据更改是否保证派生数据重新计算与每次重新计算派生数据有关。 (注意:保持数据完整性的另一种方法是强制按计划重新计算派生数据,其中数据可能在某些时间容差下不准确.StackExchange采用这种方法的一些数字)。

在一个典型的场景中(更多的数据检索和对底层数据的更少变化),数学显然倾向于在表中保持非规范化的派生数据。

在极少数情况下,基础数据经常发生变化,但通常不会检索派生数据,这样做可能会有害。


现在,我们讨论了一个更为重要的问题:性能提升是否值得付出努力?

请注意,与所有优化一样,最大的问题是“优化甚至是值得的吗?”,因此需要考虑两个主要因素:

  1. 测量精确的性能差异并进行分析。

  2. 在您的系统大局中进行此特定优化的背景。

  3. E.g。如果查询性能的差异 - 在优化时必须首先测量 - 在缓存的派生数据和计算的数据之间是2%,实现信誉缓存列的额外系统复杂性可能不值得首先。但是,关心与不关心的门槛是什么,边际改善取决于你的应用程序的大局。如果您可以采取措施在不同的地方将查询性能提高10%,那么请专注于2%。如果你是谷歌并且额外2%的查询性能需要20亿美元的额外硬件来承担它,那么无论如何都需要进行优化。

答案 1 :(得分:1)

实际上没有明确的答案,因为它取决于很多因素,例如网站的数量和显示声誉的频率(即仅在他们的个人资料页面上或在他们的用户名的每个实例旁边,到处都是) 。唯一真正的答案是“当它变得太慢”时;换句话说,您可能需要测试这两种情况并获得一些真实世界的性能统计数据。

就我个人而言,我会在这种特殊情况下进行非规范化,并且在upvote表上有一个插入触发器或者一个更新denromalized信誉列的定期更新查询。在页面刷新之前,某个人的代表会说“204”而不是“205”吗?它真的真的是世界末日吗?

答案 2 :(得分:0)

我只是想对DVK在上面的响应中所涵盖的数据完整性问题提出另一个角度。考虑其他系统是否需要访问/计算派生数据 - 甚至是报告系统这样简单的事情。如果其他系统需要使用派生值或更新upvote值,那么您可能需要考虑如何重用计算代码或如何确保派生值始终更新,无论系统如何更改upvote。