扩展高分数据库
我为网络游戏提供了一个简单的高分服务,并且它比预期更受欢迎。 高分是一个web服务,它使用带有简单表的MYSQL后端,如下所示。 每个高分记录都作为一行存储在此表中。 问题是,对于大于140k行的行,我发现某些关键查询的速度变慢,以致于很快无法处理请求。
主表看起来像这样:
+----------+---------------+------+-----+---------+----------------+ | 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"
其次是a
"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)。 现在,无论我使用什么偏移量,所有查询都运行得非常快。 解释显示没有额外的排序正在完成,它看起来很容易处理所有的流量。
看到如何没有接受者,我会给它一个镜头。 我来自SQL Server背景,但适用相同的想法。
一些一般性观察:
100万行真的不是那么多。 我创建了一个拥有1,000,000行样本数据的表,即使只有一个索引(游戏ASC,时间DESC和级别DESC),所有查询的运行时间都不到1秒。
(我不确定的唯一部分是playerId,查询表现得非常好,以至于playerId似乎不是必需的,也许你可以在聚集索引的末尾添加它。)
链接地址: http://www.djcxy.com/p/50453.html