用于存储用户分数的Mysql数据库设计

时间:2012-10-21 15:47:43

标签: mysql database-design database-schema ranking

我正在创建一个网站,其中所有用户都有一个每天更新的分数。我可以轻松地从这个分数创建排名,但是我希望能够创建一周或一个月的“热门”列表等。

我的蛮力设计将是每个用户的每一天,计算他们的分数并将其放入“分数”表中。所以每天Scores表会增加用户数量。我可以根据他们在任何时间段的得分增量对用户进行排名。

虽然我相信这在技术上会起作用,但我觉得必须采用更复杂的方法来做到这一点,对吧?或不?我觉得像一个Scores表,每天增加的用户数量不会像其他网站那样增加。

2 个答案:

答案 0 :(得分:3)

通过不存储任何得分快照,您可以获得最大的灵活性。相反,会记录增量分数。

如果你有这样的表:

用户

  • USER_ID
  • 名称
  • personal_high_score
  • {每个用户存储一次的其他内容}

<强> SCORE_LOG

  • score_log_id
  • user_id(FK to USER)
  • DATE_TIME
  • scored_points

现在,您可以通过以下简单查询获得用户的累积分数:

select sum(scored_points)
from SCORE_LOG
where user_id = @UserID
  and date_time <= @PointInTime

您还可以轻松获得一段时间内排名靠前的得分者,例如:

select
  user_id
, sum(scored_points)
from SCORE_LOG
group by
  user_id
where date_time >= @StartOfPeriod
  and date_time <= @EndOfPeriod
order by
  sum(scored_points) desc
limit 5

如果您开始制作并发现您在实践中遇到性能问题,那么您可以考虑对任何统计信息的快照进行非规范化。这些快照统计信息的问题在于它们可能与源数据不同步,因此您需要一种策略来定期重新计算快照。

这几乎是一个老生常谈(认为它是墨菲定律的必然结果),如果你有两个真理来源,你最终会得到两个“真理”。

答案 1 :(得分:2)

巴兰卡的评论是正确的,你需要确保你不会在任何可能的情况下复制任何数据。

但是,如果您希望能够恢复某些旧用户的分数,或者可能能够选择一天并查看谁在某一点上名列前茅,即动态报告,那么您将需要记录每条记录单独在一个日期旁边。为此提供单独的表将非常有用,因为您可以通过SQL从现有用户数据中推断出每日得分,并随时将其输入到表中。

您的决定是您希望在历史记录中保留多少用户记录以及记录多长时间。我写了下面的想法,“热门列表”将是前5名用户,您可以每天/每月运行CRON作业或计划任务来运行插入,并清理非常旧的数据。

用户

  • ID
  • 用户名
  • 得分

<强> score_ranking

  • ID
  • user_id(我们使用id而不是所有用户信息进行规范化)
  • score_at_the_time
  • date_of_ranking

因此,要生成单个数据排名,您可以插入此表。类似的东西:

INSERT INTO
  `score_ranking` (`user_id`, `score_at_the_time`, `date_of_ranking`)
SELECT
  `id`, `score`, CURDATE()
FROM
  `users`
ORDER BY
  `score` DESC
LIMIT
 5

要读取特定日期(或日期范围)的数据,您可以执行以下操作:

SELECT * FROM score_ranking 
WHERE date_of_ranking = 'somedate' 
ORDER BY score_at_the_time DESC