我有一个用于高分的MySQL表。该表包含150,000,000多个条目。
为简单起见,我们假设结构highscore (id, userId, itemId score)
。 userId和得分应该是直观的,我需要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
答案 0 :(得分:0)
我的猜测是研究你可以找到问题所在的EXPLAIN
,但是想象一下,你可以按照tricks
在我的游戏体验中,一些排名并未实时更新,因为这会耗费时间。所以你在时间窗口更新排名。
所以如果你知道排名过程需要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;
然后在userId
中为itemId
和temp_rank
创建一个索引,以便您的所有SELECT
都应该立即完成。