存储/计算用户分数的最佳方法是什么?

时间:2009-05-07 21:59:10

标签: sql mysql database database-design

我希望为一个网站设计一个数据库,用户可以通过该网站获得执行某些活动的积分(声誉),并且正在努力应对数据库设计。

我计划保留用户所做事情的记录,这样他们可能会为他们提交的项目提供25分,每个提交30条评论1分,以及另外10条优秀的奖励积分!

显然,所有的数据都会存在,但是为了获得每个用户的总得分(我想在他们的用户名旁边显示)(以关卡的形式),似乎很多或者都在查询。例如,对提交的项目表的查询以获取该用户的每个项目的分数,对评论表的查询等。如果需要对页面上提到的每个用户完成所有这些....大量的查询!

我曾考虑在用户表中保留一个分数,这看起来要快得多,但是我已经知道存储可以从其他数据计算的数据 BAD!< /强>

我看过很多网站都做类似的事情(甚至堆栈溢出也类似)所以我认为必须有一个“最佳实践”。任何人都可以建议它可能是什么?

任何建议或评论都会很棒。谢谢!

4 个答案:

答案 0 :(得分:4)

我认为这绝对是一个很好的问题。我必须构建与此类似行为的系统 - 尤其是当经常访问具有分数的表时(如在您的场景中)。以下是我给你的建议:

首先,创建一些如下所示的表(我使用的是SQL Server最佳实践,但是如果您认为合适,请将它们命名):

UserAccount          UserAchievement
 -Guid (PK)           -Guid (PK)
 -FirstName           -UserAccountGuid (FK)
 -LastName            -Name
 -EmailAddress        -Score

完成此操作后,继续创建一个类似于以下内容的视图(不,我没有验证过这个SQL,但它应该是一个好的开始):

SELECT [UserAccount].[FirstName]      AS FirstName,
       [UserAccount].[LastName]       AS LastName,
       SUM([UserAchievement].[Score]) AS TotalPoints
FROM [UserAccount]
INNER JOIN [UserAchievement]
     ON [UserAccount].[Guid] = [UserAchievement].[UserAccountGuid]
GROUP BY [UserAccount].[FirstName],
         [UserAccount].[LastName]
ORDER BY [UserAccount].[LastName] ASC

我知道你已经提到了一些关于性能和大量查询的问题,但如果你构建一个这样的视图,你就不需要多个。我建议不要将其视为物化视图;相反,只需索引您的表,以便您需要的查找(实际上是UserAccountGuid)将实现表中的快速求和。

我还要补充一点 - 如果您的UserAccount表变得庞大,您可以考虑使用稍微更智能的查询,该查询将包含您需要进行汇总的帐户名称。这样,当您只在页面上显示3-10个用户的信息时,就不会将大量数据集返回到您的网站。我不得不考虑更多关于如何优雅地做到这一点,但我建议远离“IN”语句,因为这将调用表格的线性搜索。

答案 1 :(得分:1)

对于非常高的读/写比率,非规范化是一个非常有效的选项。您可以使用索引视图,并且数据将以声明方式保持同步(因此您永远不必担心存在错误的分数数据)。缺点是它保持同步..所以商店总数的更新是提交分数动作的同步方面。这通常会很快,但这是一个设计决定。如果你自己反规范化,你可以选择是否想要某种延迟更新系统。

就个人而言,我会使用索引视图进行启动,然后如果您的需要,您可以使用具体的表格无缝地替换它。

答案 2 :(得分:0)

在过去,我们总是使用某种夜间或周期性的cron作业来计算当前得分并将其保存在数据库中 - 有点像活动表上的SUM的持久视图。像大多数“最佳实践”一样,它们只是指导方针,在特定领域偏离特定的强硬实践往往更好,更实际。

另外,如果您使用cron作业,它并不是真正的偏差,因为它最好被视为存储在数据库中的缓存。

答案 3 :(得分:0)

如果您有单独的分数表,则可以在每次提交项目或用户发布评论时更新它。您可以使用触发器或站点代码执行此操作。

用户分数会不断更新,并可以快速查询显示。