我有一个用于高分的 MySQL 表。该表包含 150,000,000 多个条目。
为了简单起见,我们假设结构为highscore (id, userId, itemId Score)
。 userId 和 Score 应该很直观,但我需要 itemId
因为游戏可以使用大约 100 个不同的元素来完成,并且我想找出使用特定元素的特定用户的阶梯排名。 (例如:使用项目 67 的用户 123456 的得分为 1337,因此该项目的排名为#987654)
例如,我有一个 userId 12345
,想看看他在全局天梯列表中与 itemId 67
的排名如何。
在其他 stackoverflow 线程上,我找到了这样的解决方案:
SELECT id, userId, itemId, score, rank
FROM
(
SELECT id, userId, itemId, score, @n := IF(@g = score, @n, @n + 1) rank, @g := score
FROM highscore(SELECT @n := 0) i
ORDER BY score DESC
) q
where userId = 12345 and itemId = 67
但是这个查询需要314秒才能运行(我有id
、score
、userId、itemId
和itemId的mysql索引
)。我需要一个解决方案,允许人们实时查找该项目的运行的全局排名。
是否有机会找到一个查询,在合理的时间内正确地让我在这里获得排名? (<0.1 秒)如果需要,我也对结构和索引更改持开放态度。
如果无法及时得到,还有什么其他办法呢?使用 cronjob 每 24 小时克隆一次表,添加行rankByItem 并为每一行计算它?对我来说听起来更加不必要的工作。
希望有人有想法。
对上述查询进行解释扩展(抱歉,我不知道如何在这里制作表格。我试图使其可读):
+------------------------------------------------------------------------------+
| id select_type table type possible_keys key key_len ref rows filtered Extra |
+------------------------------------------------------------------------------+
| 1 PRIMARY <derived2> ALL NULL NULL NULL NULL 215011943 100.00 Using where |
| 2 DERIVED <derived3> system NULL NULL NULL NULL 1 100.00 Using filesort |
| 2 DERIVED highscore ALL NULL NULL NULL NULL 215033733 100.00 |
| 3 DERIVED NULL NULL NULL NULL NULL NULL NULL NULL No tables used |
+------------------------------------------------------------------------------+
创建表:
CREATE TABLE `highscore` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`userId` int(10) unsigned NOT NULL,
`itemId` smallint(3) unsigned NOT NULL,
`date` date NOT NULL,
`score` smallint(5) unsigned NOT NULL,
# ...
PRIMARY KEY (`id`),
UNIQUE KEY `user_item` (`userId`,`itemId`),
KEY `item` (`itemId`),
KEY `score` (`score`)
) ENGINE=InnoDB AUTO_INCREMENT=215042396 DEFAULT CHARSET=utf8
最佳答案
我的猜测是研究EXPLAIN
,你可以找到问题所在,但想象一下,你可以按照一些技巧
解决它
在我的游戏体验中,有些排名没有实时更新,因为这很耗时。因此,您可以更新时间窗口中的排名。
所以如果你知道排名过程需要 5 分钟。您每 5 分钟创建一个临时表
CREATE TABLE temp_rank as
SELECT id,
userId,
itemId,
score,
@n := IF(@g = score, @n, @n + 1) rank,
@g := score
FROM highscore, (SELECT @n := 0, @g := '') i
ORDER BY score DESC;
然后在 temp_rank
中为 userId
和 itemId
创建一个索引,以便您的所有 SELECT
应该立即完成。
关于mysql - 从巨大的无序分数MySQL表中获取排名,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40353180/