我有一個簡單的高分服務的在線遊戲,它已經變得比預期更受歡迎。高分是一個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