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

Mysql 在数据库中,何时存储派生数据?,mysql,normalization,Mysql,Normalization,我的问题是关于非规范化。在数据库中,什么时候应该将派生数据存储在它自己的列中,而不是每次需要时都进行计算 例如,假设您有一些用户对他们的问题进行了投票。您可以在用户的个人资料上显示用户的声誉。当用户被提升投票时,您应该增加他们的声誉,还是在检索他们的个人资料时计算声誉: SELECT User.id, COUNT(*) AS reputation FROM User LEFT JOIN Question ON Question.User_id = User.id LEFT JOIN Upvo

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

例如,假设您有一些用户对他们的问题进行了投票。您可以在用户的个人资料上显示用户的声誉。当用户被提升投票时,您应该增加他们的声誉,还是在检索他们的个人资料时计算声誉:

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的权重取决于Upvote的数量,而不是投票的用户的声誉。检索其声誉的查询突然爆发:

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

这与增量解决方案的难度远远不成比例。什么时候正常化才值得呢,在这种情况下,什么时候标准化的好处会输给非标准化的好处?查询难度和/或性能?

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

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

为了获得用户的声誉,查询需要多大的处理器密集度,然后才值得使用自己的列以增量方式跟踪它

这里真的有两个问题,一个是:1这个改变是否会提高性能,2性能改进是否值得努力

至于性能是否提高,这基本上是一个标准的利弊分析

正常化的好处基本上有两个方面:

更简单的数据完整性

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

如果您使用可靠实施的解决方案(例如触发器、仅存储过程的数据更改和已撤销的直接表更改PERM等)覆盖数据完整性。。。,然后,这就变成了一个简单的计算,即验证源数据更改是否需要重新计算派生数据的成本,而不是每次重新计算派生数据的成本。注意:保持数据完整性的另一种方法是强制按计划重新计算派生数据,在这种情况下,数据在一定的时间公差下可能会不准确。StackExchange采用这种方法处理一些数字

在一个典型的场景中,对数据的检索要多得多,对底层数据的更改要少得多,数学显然倾向于将非规范化的派生数据保留在表中

在一些罕见的情况下,底层数据经常更改,但派生数据没有经常检索,这样做可能有害

现在,我们进入了一个更重要的问题:性能改进是否值得付出努力

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

测量准确的性能差异并进行总体分析

在您的系统的大图中,此特定优化的上下文


例如,如果缓存的派生数据和计算的数据之间的查询性能差异(优化时必须首先测量)为2%,那么实现信誉缓存列的额外系统复杂性首先可能不值得。但是,关心与不关心的界限取决于你的应用程序的整体情况。如果您可以在另一个地方采取措施将查询性能提高10%,请将注意力集中在这一点上,而不是2%。如果你是谷歌,额外2%的查询性能需要额外的硬件来承担20亿美元的成本,那么无论如何都需要对其进行优化。

我只是想从另一个角度谈谈数据完整性问题,DVK在上面的回应中很好地涵盖了这一问题。考虑其他系统是否需要访问/计算派生数据——即使是像报告系统这样简单的系统。如果其他系统需要使用派生值或更新upvote值,那么您可能需要考虑如何重用计算代码,或者如何确保派生值在任何系统更改upvote时都得到一致更新