3

joinこの質問が具体的すぎる場合は事前にお詫び申し上げますが、これはかなり典型的なシナリオであると思います。group byデータベースが行き詰まり、それを回避するための最良の方法です。私の具体的な問題は、以下に基づいてスコアボードを作成する必要があることです。

  • プレイ (userid,gameid,score) 40M 行
  • ゲーム (gameid) 100K 行
  • app_games (appid,gameid) つまり、ゲームはアプリにグループ化され、関連するすべてのゲームの合計であるアプリの合計スコアが 20 行未満です

ユーザーは複数回プレイでき、各ゲームの最高スコアが記録されます。クエリの作成は簡単です。いくつかのバリエーションを実行しましたが、負荷がかかると「一時テーブルのコピー」で 30 ~ 60 秒間ロックされるという厄介な傾向があります。

私に何ができる?微調整する必要があるサーバー変数はありますか、またはクエリを再構築して高速化する方法はありますか? 私が使用しているクエリの派生バージョンは次のとおりです (名前を取得するためのユーザー テーブル結合を除く)。

    select userID,sum(score) as cumscore from  
        (select userID, gameID,max(p.score) as score 
        from play p join app_game ag using (gameID)  
        where ag.appID = 1 and p.score>0
        group by userID,gameID ) app_stats 
    group by userid order by cumscore desc limit 0,20;

または一時テーブルとして:

    drop table if exists app_stats;
    create temporary table app_stats 
        select userID,gameID,max(p.score) as score 
        from play p join app_game ag using (gameID)  
        where ag.appID = 1 and p.score>0
        group by userid,gameID;
    select userID,sum(score) as cumscore from app_stats group by userid 
        order by cumscore desc limit 0,20;

次のようなインデックスがあります。

show indexes from play;
+-------+------------+----------------------+--------------+------------------+-----------+-------------+----------+--------+------+------------+---------+
| Table | Non_unique | Key_name             | Seq_in_index | Column_name      | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+-------+------------+----------------------+--------------+------------------+-----------+-------------+----------+--------+------+------------+---------+
| play  |          0 | PRIMARY              |            1 | playID           | A         |    38353712 |     NULL | NULL   |      | BTREE      |         |
| play  |          0 | uk_play_uniqueID     |            1 | uniqueID         | A         |    38353712 |     NULL | NULL   | YES  | BTREE      |         |
| play  |          1 | play_score_added     |            1 | dateTimeFinished | A         |    19176856 |     NULL | NULL   | YES  | BTREE      |         |
| play  |          1 | play_score_added     |            2 | score            | A         |    19176856 |     NULL | NULL   |      | BTREE      |         |
| play  |          1 | fk_playData_game     |            1 | gameID           | A         |       76098 |     NULL | NULL   |      | BTREE      |         |
| play  |          1 | user_hiscore         |            1 | userID           | A         |      650062 |     NULL | NULL   | YES  | BTREE      |         |
| play  |          1 | user_hiscore         |            2 | score            | A         |     2397107 |     NULL | NULL   |      | BTREE      |         |
+-------+------------+----------------------+--------------+------------------+-----------+-------------+----------+--------+------+------------+---------+
4

2 に答える 2

2

一時テーブルを作成するときの両方のクエリは、基本的にテーブル内のすべてのデータを処理する必要があると思われます (すべてを一度に実行するクエリでも同様です)。大量のデータがある場合は、少し時間がかかります。

各プレイヤーの ID と合計スコアを含む別のテーブルを維持します。プレイ テーブルを更新するたびに、サマリー テーブルも更新します。同期が取れなくなった場合は、サマリー テーブルを停止して、プレイ テーブルからデータを再作成します。(または、インフラストラクチャで既に redis を使用している場合は、そこに概要を維持できます。これには、この特定のことを非常に高速にする機能があります)。

于 2012-05-31T16:54:43.140 に答える
0

一時テーブルを作成する代わりに、代わりにビューを作成してみてください。通常のテーブルと同じようにクエリを実行できますが、ビュー内のデータが変更されたときにも更新されます。これは、テーブルを削除して毎回再作成するよりもはるかに高速です。

于 2012-05-31T16:41:32.263 に答える