2016-04-24 3 views
2

私は約20000行の "match_players"という名前の関係テーブルを持っています。 「hero_id」という名前の列があり、これはマッチで選手が選んだ英雄を表しています。すべてのフィールドが索引付けされます。痛いほど遅い自己JOIN

私は私の現在のクエリを約かかり

など、彼らは敵だった何回、彼らは同じチームにいた回数をカウントし、2人の英雄のすべての組み合わせからなる別のテーブルを構築する必要があります

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 

更新:

私はマッチにあったヒーローのみが必要なので、私は次のようにクエリを更新しました。それははるかに高速です。私はそれが数10分の1秒で完了すると思います。

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 

私はすべての英雄の組み合わせのリストを望んでいた場合、私はまだそれについて移動する最良の方法はどのようになるか、同じ試合であるか否か、しかし、知っていただきたいと思いますか?明らかに、数千行を超えるテーブルの元のクエリでは実現不可能です。このクエリの

+0

「痛みを伴う」とは、通常、「テーブルをインデックス登録するのを忘れた」ことを意味します。 'EXPLAIN'とは何ですか? '<'節は通常問題になりますが、直接のマッチは速くなります。あなたが実際に壁にぶつかっているなら、多分これをスクリプト言語でメモリにロードし、それをそのように処理してください。 – tadman

+0

@tadman - 私は自分の投稿にEXPLAINを追加しました。 – DaiBu

答えて

0

を:

あなたはこれが発生する頻度のアイデアを得るために、このクエリを実行することもできますmatch_id)とはるかに高速です。私はそれが数10分の1秒で完了すると思います。

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 
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(*)ではなく、count(distinct match_id)が必要です。さらに重要なことは、チームの規模に応じて、パフォーマンスに大きな影響を与える可能性があることです。私は(上の参加、私は次のように私のクエリを更新し、一緒にマッチしていた英雄を必要とするので

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; 
+0

どのマッチにも重複するヒーローはありません。 1つを選択すると、プールから削除されます。複合インデックスを追加しようとします。 – DaiBu

+0

複合インデックスは役に立ちませんでした。重複するヒーローがないため、クエリではcnt = 1とcount(*)= 34190のいずれかの行が返されました。ありがとう、男。 @DaiBu。 – DaiBu

+0

。 。あなたはいくつのチームを持っていますか?平均的なチームはどれくらいの規模ですか?おそらくあなたはあまりにも多くの組み合わせを生成しているに過ぎません。 –

関連する問題