痛苦地缓慢自我加入

时间:2016-04-24 00:56:45

标签: mysql sql

我有一个名为" match_players"的关系表。有大约20000行。有一个名为" hero_id"的列。这代表了一名球员在比赛中选择了什么英雄。所有字段都已编入索引。

我需要建立另一个由两位英雄的组合组成的表,计算他们在同一个团队中的次数,他们是敌人的次数等等。

我目前的查询在8核SSD服务器上大约需要90秒。我想这与MySQL有关,在分组结果之前在内部构建所有组合的庞大表。

是否有另一种方法来收集行值的组合,也许MySQL只是扫描表格,在找到它们时记录新的组合?任何意见都表示赞赏。

表" match_players":

match_id | team | position | player_id | hero_id |

56427859 |    1 |        1 |    546107 |      17 |
56427859 |    1 |        2 |    469333 |      81 |
56427859 |    1 |        3 |    227526 |      60 |
56427859 |    1 |        4 |    193739 |      32 |
56427860 |    0 |        0 |    473923 |      11 |
56427860 |    0 |        1 |    292764 |      93 |
56427860 |    0 |        2 |    138018 |      26 |
56427860 |    0 |        3 |    326510 |      96 |

etc...

查询:

SELECT mp1.hero_id, mp2.hero_id
FROM match_players mp1
INNER JOIN match_players mp2
ON mp1.hero_id < mp2.hero_id
WHERE mp1.team = mp2.team
GROUP BY mp1.hero_id, mp2.hero_id

说明:

id | select_type | table | type | possible_keys      | key        | key_len | ref                        |  rows | Extra

 1 |      SIMPLE |   mp1 |  ALL | faction_id,hero_id |       NULL |    NULL |                       NULL | 34060 | Using temporary; Using filesort
 1 |      SIMPLE |   mp2 |  ref | faction_id,hero_id | faction_id |       1 | beta_dota_2.mp1.faction_id |  3499 | Using where

更新

由于我只需要一起匹配的英雄,我将我的查询更新为以下内容并且更快,更快。我认为它会在几分之一秒内完成。

SELECT mp1.hero_id, mp2.hero_id
FROM match_players mp1
INNER JOIN match_players mp2
ON mp1.hero_id < mp2.hero_id
WHERE mp1.team = mp2.team AND mp1.match_id = mp2.match_id
GROUP BY mp1.hero_id, mp2.hero_id

我仍然想知道,如果我想要一个所有英雄组合的列表,无论是否在同一场比赛中,最好的方法是什么?对于任何大于几千行的表格,我的原始查询显然是不可行的。

2 个答案:

答案 0 :(得分:5)

对于此查询:

SELECT mp1.hero_id, mp2.hero_id
FROM match_players mp1 INNER JOIN
     match_players mp2
     ON mp1.hero_id < mp2.hero_id AND
        mp1.team = mp2.team
GROUP BY mp1.hero_id, mp2.hero_id;

您需要match_players(team, hero_id)上的综合索引。这是一个开始的地方。

在我考虑它时,性能问题可能是由于比赛中的许多玩家选择相同的“英雄”。如果可以,那么您需要count(distinct match_id)代替count(*)进行计数。更重要的是,这会对绩效产生重大影响 - 取决于团队的规模。

您可能希望运行此查询以了解这种情况发生的频率:

select cnt, count(*)
from (select match_id, hero_id, count(*) as cnt
      from match_players
      group by match_id, hero_id
     ) mh
group by cnt
order by cnt desc;

答案 1 :(得分:0)

由于我只需要一起匹配的英雄,我将我的查询更新为以下内容(加入match_id)并且它更快,更快。我认为它会在几分之一秒内完成。

SELECT mp1.hero_id, mp2.hero_id
FROM match_players mp1
INNER JOIN match_players mp2
ON mp1.hero_id < mp2.hero_id
WHERE mp1.team = mp2.team AND mp1.match_id = mp2.match_id
GROUP BY mp1.hero_id, mp2.hero_id