2011-02-01 77 views
7

我有一個簡單的高分服務的在線遊戲,它已經變得比預期更受歡迎。高分是一個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)。現在,無論我使用什麼偏移量,所有查詢都運行得非常快。解釋顯示沒有額外的排序正在完成,它看起來很容易處理所有的流量。

+3

使用Mongo DB。這是網絡規模。 – anon 2011-02-01 03:56:41

+7

奇怪的是,它不可能downvote評論(「使用Mongo DB。這是網絡比例。」) – zerkms 2011-02-01 03:58:33

回答

4

看到如何沒有接受者,我會給它一個鏡頭。我來自SQL Server背景,但適用相同的想法。

一些一般性的意見:

  • ID列是非常沒有意義的,除非有你不告訴我們其他表/查詢不宜參加任何索引。事實上,它甚至不需要在最後的查詢中。你可以做COUNT(*)。
  • 您的聚集索引應該針對您最常見的查詢。因此,遊戲ASC,時間DESC和等級DESC上的聚集索引效果良好。按照時間排序DESC對於像這樣的歷史表格來說通常是一個好主意,通常你會對最近的東西感興趣。你也可以嘗試一個單獨的索引,排名其他方向,但我不知道這將是多少好處。
  • 你確定你需要SELECT *嗎?如果您可以選擇較少的列,則可以創建包含SELECT和WHERE所需的所有列的索引。

100萬行其實並不多。我創建了一個擁有1,000,000行樣本數據的表,即使只有一個索引(遊戲ASC,時間DESC和級別DESC),所有查詢的運行時間都不到1秒。

(我不知道的是playerId的一部分。該查詢執行得非常好,playerId似乎沒有必要。或許你可以在你的聚集索引的末尾添加它。)