2011-12-16 7 views
1

LEFT JOINとサブクエリを使用して複数のテーブルからカウントを取得しているクエリがあります。アイデアはメンバーが参加しているのactivites様々なカウントを取得するためにあるスキーマがこのようになります複数の左結合のMySQLカウント - オプトマイズ

:。 PKは

をMEMBER_ID

メンバー

TABLE1 PKは FK MEMBER_ID

table2の をtbl1_id PK tbl2_id FK member_id

表3 PK tbl 27はテストIDで

SELECT t1.num1,t2.num2,t3.num3 
FROM member m 
LEFT JOIN 
(
    SELECT member_id,COUNT(*) as num1 
    FROM table1 
    GROUP BY member_id 
) t1 ON t1.member_id = m.member_id 
LEFT JOIN 
(
    SELECT member_id,COUNT(*) as num2 
    FROM table2 
    GROUP BY member_id 
) t2 ON t2.member_id = m.member_id 
LEFT JOIN 
(
    SELECT member_id,COUNT(*) as num3 
    FROM table3 
    GROUP BY member_id 
) t3 ON t3.member_id = m.member_id 
WHERE m.member_id = 27 

: FKは私のクエリは次のようになります

をMEMBER_ID 3_id。実際のクエリでは、3つ以上のテーブルが結合され、クエリが変更されたmember_idで複数回実行されます。問題は、このクエリがかなり遅く実行されることです。私は必要な情報を得るが、誰かがこれを最適化する方法を提案できるかどうか疑問に思う。どんなアドバイスも大歓迎です。どうもありがとう。

+0

これらのテーブルにはどのようなインデックスがありますか? – MatBailie

答えて

3

クエリをリファクタリングする必要があります。クエリがデータを収集する方法を並べ替えることで、これを行うことができます。どうやって?

  • 句最初
  • はここで最後

に合流適用WHERE元のクエリがある適用:

SELECT t1.num1,t2.num2,t3.num3 
FROM member m 
LEFT JOIN 
( 
    SELECT member_id,COUNT(*) as num1 
    FROM table1 
    GROUP BY member_id 
) t1 ON t1.member_id = m.member_id 
LEFT JOIN 
( 
    SELECT member_id,COUNT(*) as num2 
    FROM table2 
    GROUP BY member_id 
) t2 ON t2.member_id = m.member_id 
LEFT JOIN 
( 
    SELECT member_id,COUNT(*) as num3 
    FROM table3 
    GROUP BY member_id 
) t3 ON t3.member_id = m.member_id 
WHERE m.member_id = 27 

ここでは、私がところで

SELECT 
    IFNULL(t1.num1,0) num1, 
    IFNULL(t1.num2,0) num2, 
    IFNULL(t1.num3,0) num3 
FROM 
(
    SELECT * FROM member m 
    WHERE member_id = 27 
) 
LEFT JOIN 
( 
    SELECT member_id,COUNT(*) as num1 
    FROM table1 
    WHERE member_id = 27 
    GROUP BY member_id 
) t1 ON t1.member_id = m.member_id 
LEFT JOIN 
( 
    SELECT member_id,COUNT(*) as num2 
    FROM table2 
    WHERE member_id = 27 
    GROUP BY member_id 
) t2 ON t2.member_id = m.member_id 
LEFT JOIN 
( 
    SELECT member_id,COUNT(*) as num3 
    FROM table3 
    WHERE member_id = 27 
    GROUP BY member_id 
) t3 ON t3.member_id = m.member_id 
; 

新しいクエリです変更されたmember mSELECT * FROM member m WHERE member_id = 27に変更する必要がある場合は、メンバー27に関する情報が必要です。IFNULL関数を各結果に追加して、カウントがNULLの場合は0を生成します。

あなたが

  • MEMBER_IDがプライマリ
  • MEMBER_IDがTABLE1、table2の中にインデックスされるメンバテーブルのキー、および表3

はそれを試してみるです絶対に確認する必要があります! !

+0

これに関する証拠はありますか?これは私の経験に違いはありません... WHERE句は、それが結合される前に最初のテーブルをフィルタリングし、結合が暗黙的にその条件を実行します。また、私の知る限り、オプティマイザは、それが破棄されることを認識しているレコードを盲目的に集計することはありません。 – MatBailie

+0

@Dems:私は実際に経験的な例を持っています。ここでは、MySQL Optimizerの言葉にもかかわらず、クエリをリファクタリングする方法について投稿しました。http://stackoverflow.com/a/6023217/491757 – RolandoMySQLDBA

+0

私はそれを見過ごす時間しかありません。私はそれがプレーで同じメカニズムであると確信していない。私が推奨できるのは、OPが実際のデータで試してみることです。それがうまくいけば、@RolandoMySQLDBAクレジットを与えてください:) – MatBailie

2

あなたのスキーマと何をインデックスにやったを知らなくても、これはより高速にする1つの可能な方法がある:今すぐ

SELECT (select ifnull(count(*),0) from table1 where table1.member_id = m.id) as num1, 
(select ifnull(count(*),0) from table2 where table2.member_id = m.id) as num2, 
(select ifnull(count(*),0) from table3 where table3.member_id = m.id) as num3 
from member m 
WHERE m.member_id = 27 

、これは私が何も知らないという理由だけで、少し危険な勧告ですあなたのDBについて、あるいは他に何が実行されているのか、あるいはボトルネックがどこにあるのかを調べます。

一般的に、より良い回答を得るためには、問合せに説明計画を掲載することをお勧めします。

+0

相関サブクエリは、OP形式のJOINと比較して有益に機能することはめったにありません。実際、ここに与えられた例をOPに書いたのですが、私はOPが現在使っている形式を示唆していました。 – MatBailie

+0

@Dems - 私のテストシステムOP形式では、テーブル1、テーブル2、テーブル3のフルテーブルスキャンが行われましたが、私の提案ではインデックスが正しく使用されていました。 –

+0

+1はあなたの答えがより簡潔であるためです。私の答えは少し余分な手荷物が付属して認めます。私の 'm.member_id = 27'を各サブクエリに挿入するだけで、IMHOを得るために一時テーブルが速くなります。 PHP開発者がこの手荷物をコード化した場合、メリットがあります。あなたの質問はその畳み込みをすべてスキップします。 – RolandoMySQLDBA

0
SELECT num1, num2, count(*) as num3 
FROM (
    SELECT member_id, num1, count(*) as num2 
    FROM (
    SELECT member_id, count(*) as num1 
    FROM member 
    LEFT JOIN table1 USING (member_id) 
    WHERE member_id = 27) as m1 
    LEFT JOIN table2 USING (member_id)) as m2 
LEFT JOIN table3 USING (member_id); 
関連する問題