0

我有一个包含字段 id、投票(针对每个用户)、评分的表格。

任务:根据对他和其他人的投票计算用户评分。也就是我每次更新字段投票需要重新计算字段评分。

这意味着有些人可以排在第三位。投票给他,他将获得第二名,反之亦然 - 从 2 到 3。(在评级领域)

如何解决这个问题呢?每次更新字段以计算用户对 php 的评分并在 mysql 中进行大量更新查询是非常昂贵的。

4

5 回答 5

1

嗯,这取决于很多因素

  1. 您是否有一个呈指数级增长的大型系统?
  2. 您是否需要历史报告的投票数据?
  3. 用户投票时需要注册吗?
  4. 该系统会在整个系统生命周期中仅用于一种投票类型,还是会针对不同主题进行更多投票?

如果所有答案都为“” ,那么您当前的更新方法将可以正常工作。无论如何,只要确保您应用最佳编码和 MySQL 表实践即可。

假设您的大部分或全部答案都是“是”,那么我将建议以下内容:

  • 每次进行投票时,都会将INSERT记录记录到您的表格中
  • 使用INSERT,添加时间戳,如果不可能,则添加用户 ID,然后可能是 IP 地址/位置
  • 从 vote_subject 表中分配一个主题 ID 作为外键。在此表中存储投票的主题和日期
  • 现在您可以创建一个SELECT可以计算选票并计算评分的语句。投票计数列表顶部的人将在SELECT. 此外,您可以过滤每个主题、每天、每个用户,并且您还应该能够根据所需的结果确定音量。

当然,所有这些都取决于您的系统将来如何扩展。这可能有点矫枉过正,但值得考虑。

于 2012-09-21T16:58:08.653 回答
1

如果您想在没有评级列的情况下通过选择获得评级,那么这就是方法。但是从性能的角度来看,我不能保证这将是您的最佳选择。它的工作方式是,如果两个用户的票数相同,他们将获得相同的评分,然后它将跳过下一个不同评分所需的数字:

set @rating:=0;
set @count:=1;

select id,
case when @votes<>votes then @rating:=@rating+@count
else @rating end as rating,
case when @votes=votes then @count:=@count+1
else @count:=1 end as count,
@votes:=votes as votes
from t1
order by votes desc

sqlfiddle

这为您提供了一个可以忽略的额外列,或者您可以将此选择包装到子查询中并具有:

select t2.id,t2.votes,t2.rating from (
select id,
case when @votes<>votes then @rating:=@rating+@count
else @rating end as rating,
case when @votes=votes then @count:=@count+1
else @count:=1 end as count,
@votes:=votes as votes
from t1
order by votes desc) as t2

但是sqlfiddle奇怪地给出了不一致的结果,所以你必须做一些测试。如果有人知道为什么会这样,我会很想知道原因。

如果您只想获得一个用户的评分,那么执行子查询选项并在where后面使用 afrom应该会给您想要的结果。sqlfiddle - 但同样,结果不一致,运行它几次,有时它给出的评级为 10,其他时间为 30。我认为在你的数据库中进行测试以查看会发生什么将是最好的。

于 2012-09-21T17:05:14.147 回答
0

我建议在查询数据时这样做。它会简单得多。按票数降序排列。

也许在查询数据时创建一个视图并使用该视图。

你可以尝试这样的事情:

SET @rank := 0

select id, count(*) as votes, @rank := @rank + 1
from users
group by id
order by votes desc

或者

SET @rank := 0

select id, votes, @rank := @rank + 1
from users
order by votes desc
于 2012-09-21T16:37:22.337 回答
0

不使用字段 id、votes 和 rating,而是将表更改为具有字段 id、rating_sum 和 rating_count。每次你有一个新的评级时,你都会像这样查询数据库:

    "UPDATE `ratings` SET `rating_count` = `rating_count` + 1, `rating_sum` = `rating_sum`+ $user_rating WHERE `id` = $id"

现在评分只是平均值 -> rating_sum / rating_count。不需要有一个带有评级的字段。

此外,为了防止用户多次评分,您可以创建一个名为 rating_users 的表,该表将有两个外键 users.id 和 rating.id。主键将是(users.id,ratings.id)。因此,每次用户首先尝试评分时,您都会检查此表。

于 2012-09-21T16:45:52.920 回答
0

是的,聚合很昂贵。您可以每五分钟左右更新一次排名表并从那里查询。您现在可能已经进行的查询是这样的:

select id, count(*) as votes
from users
group by id
order by votes desc
于 2012-09-21T16:46:31.203 回答