我有一个简单的高分服务的在线游戏,它已经变得比预期更受欢迎。高分是一个web服务,它使用带有简单表的MYSQL后端,如下所示。每个高分记录都作为一行存储在此表中。问题是,对于大于140k行的行,我发现某些关键查询的速度变慢,以致于很快无法处理请求。扩展高分数据库
主要表看起来像这样:
- ID对每个唯一的键得分纪录
- 游戏是提交的分数(目前游戏中的ID号,始终为“1” ,很快将不得不虽然支持更多的游戏)
- name是玩家的提交
- playerId显示名称是给定用户的唯一ID
- 分数是一个数字分数表示前42035
- 时间是提交时间
- 排名是一个大整数,它对给定游戏的分数提交进行了唯一排序。人们以一定的分数打平常用的是 ,所以在这种情况下,领带被谁先提交打破。因此,该字段的值等于大致为 “分数* 100000000 +(MAX_TIME - 时间)”
+----------+---------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +----------+---------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | game | int(11) | YES | MUL | NULL | | | name | varchar(100) | YES | | NULL | | | playerId | varchar(50) | YES | | NULL | | | score | int(11) | YES | | NULL | | | time | datetime | YES | | NULL | | | rank | decimal(50,0) | YES | MUL | NULL | | +----------+---------------+------+-----+---------+----------------+
的指标是这样的:
+-----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+ | Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | +-----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+ | pozscores | 0 | PRIMARY | 1 | id | A | 138296 | NULL | NULL | | BTREE | | | pozscores | 0 | game | 1 | game | A | NULL | NULL | NULL | YES | BTREE | | | pozscores | 0 | game | 2 | rank | A | NULL | NULL | NULL | YES | BTREE | | | pozscores | 1 | rank | 1 | rank | A | 138296 | NULL | NULL | YES | BTREE | | +-----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
当用户请求高分,他们通常从“按等级降序排序”中的任意一点请求75个高分。这些请求通常用于“全天候”或仅用于过去7天的分数。
典型的查询如下所示: "SELECT * FROM scoretable WHERE game=1 AND time>? ORDER BY rank DESC LIMIT 0, 75;"
并在0.00秒内运行。
但是,如果您向列表末尾请求 "SELECT * FROM scoretable WHERE game=1 AND time>? ORDER BY rank DESC LIMIT 10000, 75;"
并且运行时间为0.06秒。
"SELECT * FROM scoretable WHERE game=1 AND time>? ORDER BY rank DESC LIMIT 100000, 75;"
并且在0.58秒内运行。
看起来这样会很快开始太长时间,因为每天提交数千个新分数!
此外,还有两种其他类型的查询,用于通过排序列表中的id查找特定的玩家。 他们看起来像这样:
"SELECT * FROM scoretable WHERE game=1 AND time>? AND playerId=? ORDER BY rank DESC LIMIT 1"
接着是
"SELECT count(id) as count FROM scoretable WHERE game=1 AND time>? AND rank>[rank returned from above]"
我的问题是:什么可以做,使之成为可扩展的系统?我可以很快看到行数增长到几百万。我希望选择一些聪明的指数会有所帮助,但改善只是微乎其微。
更新: 下面是一个解释线:
mysql> explain SELECT * FROM scoretable WHERE game=1 AND time>0 ORDER BY rank DESC LIMIT 100000, 75; +----+-------------+-----------+-------+---------------+------+---------+------+--------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-----------+-------+---------------+------+---------+------+--------+-------------+ | 1 | SIMPLE | scoretable| range | game | game | 5 | NULL | 138478 | Using where | +----+-------------+-----------+-------+---------------+------+---------+------+--------+-------------+
发现的解决方案!
我已经解决了这个问题,这要归功于这个线程的一些指针。做一个聚集索引正是我所需要的,所以我将表转换为在MySQL中使用InnoDB,它支持聚簇索引。接下来,我删除了id字段,并将主键设置为(游戏ASC,rank DESC)。现在,无论我使用什么偏移量,所有查询都运行得非常快。解释显示没有额外的排序正在完成,它看起来很容易处理所有的流量。
使用Mongo DB。这是网络规模。 – anon 2011-02-01 03:56:41
奇怪的是,它不可能downvote评论(“使用Mongo DB。这是网络比例。”) – zerkms 2011-02-01 03:58:33