简体   繁体   English

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

[英]Mysql database design for storing user scores over time

I'm creating a site where all of the users have a score that is updated everyday. 我正在创建一个网站,其中所有用户都有一个每天更新的分数。 I can easily create rankings from this score, however I'd like to be able to create a "Hot" list of the week or month, etc.. 我可以轻松地从这个分数创建排名,但是我希望能够创建一周或一个月的“热门”列表等。

My brute force design would be each day for every user, calculate their score and put it into the "Scores" table. 我的蛮力设计将是每个用户的每一天,计算他们的分数并将其放入“分数”表中。 So everyday the Scores table would increase by how many users there are. 所以每天Scores表会增加用户数量。 I could rank users by their score deltas over whatever time period. 我可以通过他们在任何时间段的得分增量对用户进行排名。

While I believe this would technically work I feel like there has to be a more sophisticated way of doing this, right? 虽然我相信这在技术上会起作用,但我觉得必须采用更复杂的方法来做到这一点,对吗? Or not? 或不? I feel like a Scores table that increases everyday by how many users there are can't be the way other sites are doing it. 我觉得像一个Scores表,每天增加的用户数量不会像其他网站那样。

You get the most flexibility by not storing any snapshots of score at all. 通过不存储任何得分快照,您可以获得最大的灵活性。 Instead, record incremental scores, as they happen. 相反, 记录增量分数,因为它们发生。

If you have tables like this: 如果你有这样的表:

USER 用户

  • user_id 用户身份
  • name 名称
  • personal_high_score personal_high_score
  • {anything else that you store once per user} {每个用户存储一次的任何其他内容}

SCORE_LOG SCORE_LOG

  • score_log_id score_log_id
  • user_id (FK to USER) user_id(FK到USER)
  • date_time 约会时间
  • scored_points scored_points

Now you can get a cumulative score for a user as of any point in time with a simple query like: 现在,您可以通过简单的查询获得用户在任何时间点的累积分数,例如:

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

You can also easily get top ranking scorers for a time period with something like: 您还可以轻松获得一段时间内排名最高的得分者,例如:

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

If you get to production and find that you're having performance issues in practice , then you could consider denormalizing a snapshot of whatever statistics make sense. 如果你开始制作并发现你在实践中遇到了性能问题,那么你可以考虑对任何统计数据的快照进行非规范化。 The problem with these snapshot statistics is that they can get out of sync with your source data, so you'll need a strategy for recalculating the snapshots periodically. 这些快照统计信息的问题在于它们可能与源数据不同步,因此您需要一种策略来定期重新计算快照。

It's pretty much a truism (consider it a corollary of Murphy's Law) that if you have two sources of truth you'll eventually end up with two "truths". 这是一个老生常谈(认为它是墨菲定律的必然结果),如果你有两个真理来源,你最终会得到两个“真理”。

Barranka was on the right track with his comment, you need to make sure you are not duplicating any of the data wherever possible. 巴兰卡的评论是正确的,你需要确保你不会在任何可能的情况下复制任何数据。

However, if you are looking to be able to revert back to some old users score or possibly be able to pick out a day and see who was top at a certain point ie dynamic reporting, then you will need to record each record separately next to a date. 但是,如果您希望能够恢复某些旧用户的分数,或者可能能够选择一天并查看谁在某一点上是最高的,即动态报告,那么您将需要在旁边分别记录每个记录一个约会。 Having a separate table for this would be useful as you could deduce the daily score from the existing user data via SQL and just enter it in to the table whenever you want. 为此提供单独的表将非常有用,因为您可以通过SQL从现有用户数据中推断出每日得分,并随时将其输入到表中。

The decision you have is how many users record do you want to maintain in the history and how long. 您的决定是您希望在历史记录中保留多少用户记录以及记录多长时间。 I have written the below with the idea that the "hot list" would be the top 5 users, you could have a CRON job or scheduled task running each day/month to run the inserts and also clean out very old data. 我写了下面的想法,“热门列表”将是前5名用户,您可以每天/每月运行CRON作业或计划任务来运行插入,并清理非常旧的数据。

Users 用户

  • id ID
  • username 用户名
  • score 得分了

score_ranking score_ranking

  • id ID
  • user_id (we normalise by using the id rather than all the user info) user_id(我们通过使用id而不是所有用户信息进行规范化)
  • score_at_the_time score_at_the_time
  • date_of_ranking date_of_ranking

So to generate a single data ranking you could insert into this table. 因此,要生成单个数据排名,您可以插入此表。 Something like: 就像是:

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

To read the data for a specific date (or date range) you could then do: 要读取特定日期(或日期范围)的数据,您可以执行以下操作:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM