私はオンラインゲームのシンプルなハイスコアサービスを提供しており、予想以上に人気が高まっています。ハイスコアは、以下に示すような単純なテーブルを持つMYSQLバックエンドを使用するWebサービスです。各高得点記録は、この表の行として格納されます。問題は、> 140k行以上で、特定の主要なクエリが非常に遅くなり、すぐに要求を処理するのが遅すぎることがわかります。高得点データベースのスケーリング
メインテーブルには次のようになります。
- IDは、それぞれに固有のキーでは、レコード
- ゲームが(現在は、常に「1」に等しいスコアを提出し、ゲームのID番号で得点します、すぐに
- 名はそのプレイヤーの提出
- playerIdの表示名です)しかしより多くのゲームをサポートする必要があります与えられたユーザ
- スコアの一意のIDは、数値スコア表現EX 42035です
- 時間は提出時間です
- rankは、特定のゲームのスコア提出を一意にソートする大きな整数です。人々が特定の得点で結ぶのに共通するのは なので、その場合は、最初に提出した人物によって縛られます。したがって、このフィールドの値はほぼ等しい「* 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秒で実行されます。
これは、毎日数千の新しいスコアが提出されるように、これはすぐに長くなりすぎるようです。
さらに、他の2つのタイプのクエリがあり、特定のプレーヤを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、ランクDESC)に設定しました。現在、どのようなオフセットを使用しても、すべてのクエリは超高速で実行されます。説明では、追加の並べ替えが実行されていないことがわかり、すべてのトラフィックを簡単に処理できるように見えます。
使用Mongo DB。それはWebスケールです。 – anon
コメントを下落させることができないのは奇妙です(「Mongo DBを使用してください、それはWebスケールです」) – zerkms
@ user509841:いくつか説明してください。 – zerkms