可能重复:
Mysql rank function
我正在建立一个排名网站,每个用户将根据级别拥有唯一的排名。 #1是最好的排名,因为有35万用户,最差排名将是#350000。
没有用户可以拥有与其他人相同的排名。现在,添加新用户时,会计算其级别。经过计算,脚本将“重建”排名,逐个浏览每个用户,并计算他们的新排名。
以下是对查询的解释:
这是我目前的剧本:
function RebuildRanks() {
$qD = mysql_query("SELECT `Id`,`RankNum` FROM `Members` ORDER BY `Rank` DESC, `Id` ASC");
$rowsD = mysql_num_rows($qD);
$curRank = 0;
for($x = 1; $x <= $rowsD; $x++) {
$rowD = mysql_fetch_array($qD);
$curRank++;
if($rowD['RankNum'] != $curRank) {
if($curRank != 0) {
mysql_query("UPDATE `Members` SET `RankNum`='$curRank' WHERE `Id`='".$rowD['Id']."'");
}
}
}
return true;
}
拥有350,000名用户,这往往会非常缓慢。基本上,在数据库中, Rank (“ORDER BY`Cop` DESC”)是他们的级别,因此查询将对它们进行排序。不幸的是,其余的过程很慢。
以这种方式处理所有350,000个用户大约需要97秒。是否有任何可能的解决方案来更有效,更快地运行?
答案 0 :(得分:2)
您为新用户计算NewNum,然后在此
之后递增所有数字 UPDATE Members SET Rank = Rank+1 WHERE Rank > NewNum
编辑将RankNum更改为Rank。我在编辑后审核了问题
答案 1 :(得分:1)
随着用户群的增长,您的RebuildRanks()函数将继续成为您的性能瓶颈;你最好的办法是设计一个系统,避免每次新用户加入时重新排名。以下是可能有所帮助的示例解决方案:
添加一个新表(ScoreMap),它是用户按其分数排序的哈希值(使用此术语而非“排名”来消除歧义)。
CREATE TABLE ScoreMap (
Score BIGINT NOT NULL,
Id BIGINT NOT NULL,
UNIQUE INDEX (Score),
UNIQUE INDEX (Id)
);
当新用户加入时,计算他们的分数并插入此新表中。如果分数发生冲突,你可以解决这个问题(如果没有两个用户可以拥有相同的RankNum,你必须具有某种类型的打破平局功能;根据需要在此表中移动用户。)
现在查询ScoreMap表:
SELECT COUNT(*) FROM ScoreMap WHERE Score >= [the score you just calculated]
这是您的新用户的RankNum。得分低于新用户的每个人的Rank都会增加1,您可以在登录时立即定期更新,将缓存放在前面等等。
PS:将你的Rank评分函数规范化为0到非常高的数字(例如万亿)之间的BIGINT。这将有助于您在插入新表时避免冲突。你想在这个范围内进行均匀分布拍摄,因为你基本上使用得分作为散列函数。
答案 2 :(得分:0)
一种方法是使用如下的查询语句(未经测试):
UPDATE `Members`
SET `RankNum` = (@newRank := @newRank + 1)
ORDER BY `Rank` DESC, `Id` ASC, @newRank := 0
同时更新和处理订单。