简介
我有一个使用排名的游戏高分榜。得分表表示当前的高分和玩家信息,并且最近的表表示用户的所有最近发布的分数,其可能是或可能不是新的最高分。
排名下降是通过计算玩家当前排名减去他们在达到最新最高分时的排名来计算的。
排名增加的计算方法是计算玩家在达到最新最高分时的排名减去他们达到之前最高分时的排名。
最后,如代码所示:"highcharts": "v4.0.4",
的问题
我使用以下两个查询结合一些PHP代码来计算排名变化。它工作得很好,但有时有点慢。
是否有办法优化或组合两个查询+ PHP代码?
我创建了第一个查询的SQL小提琴:http://sqlfiddle.com/#!9/30848/1
表中已经填充了内容,因此不应更改其结构。
这是当前的工作代码:
$change = ($drop > 0 ? -$drop : $increase);
答案 0 :(得分:3)
如果您将当前的最高分数分成新表,而所有原始数据在最近的分数中都可用..您已有效地生成了汇总表。
为什么不继续总结和总结您需要的所有数据?
这只是一个你知道什么以及何时可以知道它的案例:
我会更改您的分数表以包含两个新列:
在更新/插入每一行时调整这些列。 看起来您已经有了可用于为第一次迭代重新配置此数据的查询。
现在您的查询变得更加简单
从得分中获得排名:
MvcHtmlString
来自用户名:
SELECT COUNT(*) + 1 rank
FROM scores
WHERE score > :score
等级变化变为:
SELECT COUNT(*) + 1 rank
FROM scores s1
JOIN scores s2
ON s2.score > s1.score
WHERE s1.username = :username
<强>更新强>
如果您坚持按时间分隔,如果您尚未更新该行,这将适用于新行:
$drop = max($current_rank - $rank_on_update, 0);
$increase = max($old_rank_on_update - $rank_on_update, 0);
$change = $drop ? -$drop : $increase;
另一个查询将成为:
SELECT COUNT(*) + 1 rank
FROM scores
WHERE score >= :score
但我至少会尝试结合性能:
SELECT COUNT(*) + 1 rank
FROM scores s1
JOIN scores s2
ON s2.score > s1.score
OR (s2.score = s1.score AND s2.time < s1.time)
WHERE s1.username = :username
SELECT SUM(count) + 1 rank
FROM (
SELECT COUNT(*) count
FROM scores s1
JOIN scores s2
ON s2.score > s1.score
WHERE s1.username = :username
UNION ALL
SELECT COUNT(*) count
FROM scores s1
JOIN scores s2
ON s2.score = s1.score
AND s2.time < s1.time
WHERE s1.username = :username
) counts
上的索引会对此有所帮助。
就个人而言,我会让自己头疼并保持同等级别(我相信相当标准)。如果你希望人们能够声称首先吹牛的权利,请确保按时间顺序排列ASC任何分数图表并在显示中包含时间。
答案 1 :(得分:0)
我花了很多时间试图弄清楚等级逻辑是什么,并对其进行评论。与此同时,这是一个可以对您的数据运行的连接查询 - 我认为您的解决方案会产生这样的效果:
SELECT s.username, count(*) rank
FROM scores s LEFT JOIN recent r ON s.username != r.username
WHERE r.istopscore
AND r.score >= s.score
AND r.time <= s.time
AND (r.score-s.score + s.time-r.time)
GROUP BY s.username
ORDER BY rank ASC;
+----------+------+
| username | rank |
+----------+------+
| Beta | 1 |
| Alpha | 2 |
| Echo | 3 |
+----------+------+
(请注意,最后一个AND只是为了确保您不会考虑r.score == s.score&amp;&amp; r.time == s.time - 我猜这将是&#34领带&#34;游戏?)
答案 2 :(得分:0)
我不是MySQL人,但我认为在任何RDBMS中使用自联接进行排名都是不好的做法。您应该考虑使用排名功能。但是MySQL中没有排名功能。但有workarounds。
答案 3 :(得分:0)
为了向前推进,必须在此进行一些假设。我假设分数表每个用户名只有一个条目&#39;这在某种程度上等同于昵称。
试试这个,
如果我有一个正常工作的数据库,这将很快找出并测试,但基本上你正在进行“查询”。您正在所选字段中运行,并且您正在构建包含所有记录的临时表并将其过滤掉。
select a.nickname
, count(distinct b.username) as rank
, t.time
, t.username
, t.score
from
(
select
a.nickname
, b.username
from (select * from scores where nickname=? ) a
left join (select * from recent where istopscore = 1) as b
on (
b.score > a.score and b.time <= a.time -- include the b record if the b score is higher
or
b.score = a.score and b.time < a.time and a.username != b.username -- include b if the score is the same, b got the score before a got the score
)
) tmp
join scores t on (t.nickname = tmp.nickname)
where t.nickname = ?
我没有尝试解决你以后的逻辑,你可以使用相同的理论,但除非你能确认这个方法返回正确的行,否则不值得尝试。
如果您想深入了解,您应该创建一些数据集并完全设置SQL Fiddle。