4

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

我的蛮力设计是每天为每个用户计算他们的分数并将其放入“分数”表中。因此,每天有多少用户,Scores 表都会增加。我可以根据用户在任何时间段内的得分差异对用户进行排名。

虽然我相信这在技术上会起作用,但我觉得必须有一种更复杂的方法来做到这一点,对吧?或不?我觉得分数表每天都会增加多少用户,这不可能是其他网站的做法。

4

2 回答 2

4

通过根本不存储任何分数快照,您可以获得最大的灵活性。相反,记录增量分数,因为它们发生。

如果你有这样的表:

用户

  • 用户身份
  • 姓名
  • 个人高分
  • {您为每个用户存储一次的任何其他内容}

SCORE_LOG

  • score_log_id
  • user_id(FK 到 USER)
  • 约会时间
  • 得分点

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

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

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

如果你有两个真理来源,你最终会得到两个“真理”,这几乎是不言而喻的(认为它是墨菲定律的推论)。

于 2012-10-21T23:09:31.700 回答
2

Barranka 的评论是正确的,您需要确保尽可能不复制任何数据。

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

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

用户

  • ID
  • 用户名
  • 分数

score_ranking

  • ID
  • user_id(我们使用 id 而不是所有用户信息进行标准化)
  • score_at_the_time
  • 排名日期

因此,要生成单个数据排名,您可以将其插入到该表中。就像是:

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
于 2012-10-21T16:35:44.380 回答