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

我怀疑创建临时表时的两个查询基本上都需要遍历表中的所有数据(同样在你的 do-everything-at-once 查询中)。如果你有很多数据,那只需要一点时间。

我会维护一个单独的表格,其中包含每个玩家的 ID 和总分。每当您更新播放表时,也要更新汇总表。如果它们不同步,只需停止汇总表并从播放表重新创建数据。(或者如果你已经在你的基础设施中使用了 redis,你可以在那里维护摘要——它具有使这个特定的东西变得非常快的功能)。

于 2012-05-31T16:54:43.140 回答
0

与其制作临时表,不如尝试制作一个视图。您可以像查询普通表一样查询它,但它也会在视图中的任何数据发生更改时更新。这比每次删除表并重新创建它要快得多。

于 2012-05-31T16:41:32.263 回答