2012-04-05 9 views
1

私は現在、2つのテーブルからメトリクスデータを選択するクエリを取得していますが、1つは所有プロジェクト、もう1つはユーザーはアクセス権を持っています)。MySQL - 左結合を避けるリレーショナルデータを選択する最速の方法

SELECT v.`projectID`, 
(SELECT COUNT(m.`session`) 
    FROM `metricData` m 
    WHERE m.`projectID` = v.`projectID`) AS `sessions`, 
(SELECT COUNT(pb.`interact`) 
    FROM `interactionData` pb WHERE pb.`projectID` = v.`projectID` GROUP BY pb.`projectID`) AS `interactions` 
FROM `medias` v 
LEFT JOIN `projectsExt` pa ON v.`projectsExtID` = pa.`projectsExtID` 
WHERE (pa.`user` = '1' OR v.`ownerUser` = '1') 
GROUP BY v.`projectID` 

これは、1〜2秒の時間がかかります。これは明らかにマルチ左結合シナリオです。しかし、私は速度を改善するためにいくつかのアイデアを持っており、考えが原則どんなものかと思っていました。 Do-I: -

  • クエリでリストを選択してから、結合を実行するのではなく、データを取得してください。これがどのように機能するかはわかりません。
  • 別のクエリでselectを実行してprojectIDを取得し、その後、各projectIDでクエリを実行します。これにより、何百という潜在的に何千ものリクエストが発生する可能性がありますが、処理にはより良いかもしれませんか?
  • 他のアイデア?
+1

試してみてください!また、索引を試して、あなたが説明計画から得たものを見てください。 – halfer

+0

ええと、ちょっとここの経験に基づいてより広範なアドバイスを探しています。私はもちろんインデックスを持っています。 – waxical

+0

OKですが、あなたが説明プランを作成してここに結果を投稿すると、mysqlの専門家(私ではありません:-)は、調整が必要なものをより良く知ることができます。 – halfer

答えて

3

ここでは二つの質問があります:

  1. は、どのように私は左結合を避けることができる方法を2秒未満
  2. の私の結果を得ることができます。

#1に正しく答えるには、さらに情報が必要です。この特定の問合せの説明計画などの技術情報は、適切な開始です。あなたがアクセスするすべてのテーブルのSHOW CREATE TABLEと、そこに含まれる行の数があればさらに優れています。

さらに機能的な情報もありがとうございます。答えようとしている質問は何ですか? 「1」になっていることであるのいずれか

  1. 一致する行がprojectsExtではありません、medias.ownerUserは等しくなければなりません、その場合には「1」(:今、あなたがMEDIASの異なる2組を見ているようです)?ところで
  2. を文字列であるかprojectsExt.userが「1」に等しくなければならないためprojectsExtに1つのmathching行が正確に存在する(「1」ところで列ことになっていることである?)欠如によって

#1に答えるのに十分な情報があれば、私は#2に答えることができます - "左への参加を避ける方法"。答えは:2つのセットのUNIONを書いてください。一つは一致があり、もう一つは一致がないものです。

SELECT v.`projectID` 
,  (
     SELECT COUNT(m.`session`) 
     FROM `metricData` m 
     WHERE m.`projectID` = v.`projectID` 
     ) AS `sessions` 
,  (
     SELECT COUNT(pb.`interact`) 
     FROM `interactionData` pb 
     WHERE pb.`projectID` = v.`projectID` 
     GROUP BY pb.`projectID` 
) AS `interactions` 
FROM ( 
    SELECT  v.projectID 
    FROM medias 
    WHERE ownerUser = '1' 
    GROUP BY projectID 
    UNION ALL 
    SELECT  v.projectID 
    FROM medias v 
    INNER JOIN projectsExt pa 
    ON   v.projectsExtID = pa.projectsExtID 
    WHERE  v.ownerUser != '1' 
    AND  pa.user = '1' 
    GROUP BY v.`projectID 
) v 
0

左の結合にすべてをリファクタリングしようとしましたか?あなたがいつも同じ分野でどのようにグループ化しているかを見ると、それは問題ではありません。それを試して、EXPLAINを投稿して、ボトルネックを確認してください。

サブセレクトは、ジョインよりパフォーマンスが劣ります。これは、エンジンがジョインをより高度に最適化できるためです。実際、サブセレクトは、通常、可能であれば、エンジンによってジョインに書き換えられます。

親指のルールとして、クエリを分割することは得られません。オーバーヘッドでオプティマイザを混乱させるだけです。いつものように、このルールの例外はありますが、あなたが伝統的にやっていることをして、あなたがそのようなアプローチを熱望していることを知った後で、それらが作用します。

+0

サブリストをSELECTリストにLEFT JOINとしても書いていますか?このアプローチの問題は、通常、metricDataとinteractionDataの両方に、特定のprojectIdに対して2つ以上の行がある可能性があることです。 (なぜOPはそれらのテーブルでCOUNTを行うのでしょうか?)その仮定が真である場合、metricDataとinteractionDataのマッチングセットは、主メディアセットにのみ関連し、互いに関連していないため、デカルト積を形成します。これは通常非常に高価です。その場合は、要求されたCOUNTを抽出するのは簡単ではありません。 –

+0

LEFT JOINをmetricData、次にGROUP BYといい、projectIdごとにcountを計算してからLEFT JOINをinteractDataに、次にGROUP BYを使ってinteractionDataをCOUNTに、SUMをCOUNTに合わせる内側の入れ子レベルのmetricDataしかし、これは書き直すのはかなり苦痛で、FROM節の中の複数のSELECTにもまったく効果がありません。成功することなく他の道を探ったときの価値がある。 –

関連する問題