【发布时间】:2011-02-01 03:51:50
【问题描述】:
我有一个简单的在线游戏高分服务,它比预期的更受欢迎。高分是一个使用 MYSQL 后端和一个简单表的 web 服务,如下所示。每个高分记录在此表中存储为一行。问题是,在超过 140k 行的情况下,我发现某些关键查询的速度非常慢,以至于服务请求很快就会变得太慢。
主表如下所示:
- id 是每个分数记录的唯一键
- game 是提交分数的游戏的 ID 号(目前,总是等于“1”,不过很快会支持更多游戏)
- name 是该玩家提交的显示名称
- playerId 是给定用户的唯一 ID
- score 是一个数字分数表示形式,例如 42,035
- time为提交时间
- rank 是一个大整数,它对给定游戏的分数提交进行唯一排序。这是 人们通常以一定的分数打成平手,所以在这种情况下,平局由谁先提交打破。因此该字段的值大致等于“score * 100000000 + (MAX_TIME - time)”
索引如下所示:
+-----------+------------+----------+------------- -+-------------+------------+--------------+-------- --+--------+------+------------+---------+ |表 |非唯一 |键名 | Seq_in_index |列名 |整理 |基数|子部分 |包装 |空 |索引类型 |评论 | +-----------+------------+----------+------------- -+-------------+------------+--------------+-------- --+--------+------+------------+---------+ |评分 | 0 |初级 | 1 |编号 |一个 | 138296 |空 |空 | | BTREE | | |评分 | 0 |游戏 | 1 |游戏 |一个 |空 |空 |空 |是 | BTREE | | |评分 | 0 |游戏 | 2 |排名 |一个 |空 |空 |空 |是 | BTREE | | |评分 | 1 |排名 | 1 |排名 |一个 | 138296 |空 |空 |是 | 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; +----+-------------+------------+-------+---------- -----+--------+---------+------+--------+----------- --+ |编号 |选择类型 |表|类型 |可能的键 |关键 | key_len |参考 |行 |额外 | +----+-------------+------------+-------+---------- -----+--------+---------+------+--------+----------- --+ | 1 |简单 |评分表|范围 |游戏 |游戏 | 5 |空 | 138478 |使用位置 | +----+-------------+------------+-------+---------- -----+--------+---------+------+--------+----------- --+找到解决方案!
感谢这个线程的一些指针,我已经解决了这个问题。做聚集索引正是我需要的,所以我将表转换为使用 mysql 中的 InnoDB,它支持聚集索引。接下来,我删除了 id 字段,并将主键设置为(游戏 ASC,排名 DESC)。现在,无论我使用什么偏移量,所有查询都运行得非常快。解释显示没有进行额外的排序,看起来很容易处理所有流量。
【问题讨论】:
-
使用 Mongo DB。这是网络规模。
-
奇怪的是,无法对 cmets 投反对票(“使用 Mongo DB。它是网络规模。”)
-
@user509841:解释一下。
-
...开个玩笑:xtranormal.com/watch/6995033抱歉 =)
-
为典型查询添加了解释行。
标签: mysql