【问题标题】:Scaling a High Score Database扩展高分数据库
【发布时间】: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)”
+----------+----------------+------+-----+--------- +----------------+ |领域 |类型 |空 |钥匙 |默认 |额外 | +----------+----------------+------+-----+--------- +----------------+ |编号 |整数(11) |否 |优先级 |空 |自动增量 | |游戏 |整数(11) |是 |穆尔 |空 | | |姓名 | varchar(100) |是 | |空 | | |玩家ID | varchar(50) |是 | |空 | | |分数 |整数(11) |是 | |空 | | |时间 |日期时间 |是 | |空 | | |排名 |小数(50,0) |是 |穆尔 |空 | | +----------+----------------+------+-----+--------- +----------------+

索引如下所示:

+-----------+------------+----------+------------- -+-------------+------------+--------------+-------- --+--------+------+------------+---------+ |表 |非唯一 |键名 | 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。这是网络规模。
  • 奇怪的是,无法对 cme​​ts 投反对票(“使用 Mongo DB。它是网络规模。”)
  • @user509841:解释一下。
  • ...开个玩笑:xtranormal.com/watch/6995033抱歉 =)
  • 为典型查询添加了解释行。

标签: mysql


【解决方案1】:

既然没有人接受,我就试一试。我来自 SQL Server 背景,但同样的想法也适用。

一些一般性观察:

  • ID 列几乎毫无意义,不应参与任何索引,除非您没有告诉我们其他表/查询。事实上,它甚至不需要在您的最后一个查询中。你可以做 COUNT(*)。
  • 您的聚集索引应该针对您最常见的查询。因此,关于游戏 ASC、时间 DESC 和排名 DESC 的聚集索引效果很好。按时间 DESC 排序对于像这样的历史表格通常是一个好主意,您通常对最近的内容感兴趣。您也可以尝试将排名按另一个方向排序的单独索引,但我不确定这会有多大好处。
  • 您确定需要 SELECT * 吗?如果您可以选择更少的列,则可以创建一个索引,其中包含 SELECT 和 WHERE 所需的所有列。

100 万行真的不算多。我用 1,000,000 行样本数据创建了一个像您这样的表,即使使用一个索引(游戏 ASC、时间 DESC 和排名 DESC),所有查询都在不到 1 秒内运行。

(我不确定的唯一部分是 playerId。查询执行得非常好,以至于 playerId 似乎没有必要。也许您可以将它添加到聚集索引的末尾。)

【讨论】:

  • 谢谢!如您所说,我将如何创建聚集索引?
  • 我认为你已经明白了 =) 我看到你把时间和 playerId 留在了聚集索引之外。它们有一天可能会很有用,尽管现在我想到了,做时间上升可能会更好,因为插入将发生在索引的末尾。不确定这个。或者你可以切换到 Mongo DB,因为它是网络规模 =)
猜你喜欢
  • 2011-04-18
  • 2011-12-10
  • 1970-01-01
  • 2011-06-18
  • 2015-07-08
  • 2012-10-13
  • 2017-11-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多