1

低速で実行される次のクエリがあります。「action.typeid=1」の ACTION レコードのリストを生成し、「typeid=2」の ACTION レコードが存在するかどうかもカウントします。物事を遅らせているのはこのカウントです-一時およびファイルソートを使用しています!!! 改善方法を教えてください。

EXPLAIN 
SELECT 
  action.actionid 
FROM
  ACTION 
  INNER JOIN EVENT 
    ON action.eventid = event.eventid 
  LEFT JOIN 
    (SELECT 
      COUNT(1),
      action.eventid 
    FROM
      ACTION 
    WHERE (action.typeid = '2') 
    GROUP BY action.eventid) AS act 
    ON act.eventid = event.eventid 
WHERE actiondate2 BETWEEN 20130601 
AND 20131031
AND event.siteid = 1
AND action.typeid = 1

結果を説明する

次のインデックスが存在します

CREATE INDEX idx_cusid ON `event` (cusid);
CREATE INDEX idx_actiontypeid ON `action` (typeid);
CREATE INDEX idx_actioneventid ON `action` (eventid);
CREATE INDEX idx_actiondate ON `action` (actiondate2);
CREATE INDEX idx_eventsiteid ON `event` (siteid);
4

1 に答える 1

1

サー、質問の要件はまだ不明です。

例を使用して私の混乱を説明します。

簡単なデモをご覧ください: http://sqlfiddle.com/#!2/19f52c/6

このデモには、単純化された (わかりやすくするための) データベース構造とクエリが含まれています。

質問のクエリ (デモの最初のクエリ) は、次の結果を返します。

SELECT action.actionid 
FROM ACTION 
  INNER JOIN EVENT 
    ON action.eventid = event.eventid 
  LEFT JOIN 
    (SELECT 
      COUNT(1),
      action.eventid 
    FROM
      ACTION 
    WHERE (action.typeid = '2') 
    GROUP BY action.eventid) AS act 
    ON act.eventid = event.eventid 
WHERE -- actiondate2 BETWEEN 20130601 AND 20131031 AND
 event.siteid = 1
AND action.typeid = 1
;
+ ------------- +
| actionid      |
+ ------------- +
| 1             |
| 3             |
| 5             |
+ ------------- +

ただし、上記のクエリでは、エイリアスを使用したサブクエリACTは単に...役に立たない.

クエリはこのサブクエリを実行し (時間とサーバー リソースを消費します)、その結果を無視して破棄します。

上記のクエリは、以下のクエリ (デモの 2 番目のクエリ) と同等です。サブクエリを使用せずに、質問のクエリと同じ結果を返します (時間とリソースを節約するため、パフォーマンスが大幅に向上します)。

SELECT action.actionid 
FROM
  ACTION 
  INNER JOIN EVENT 
    ON action.eventid = event.eventid 
WHERE -- actiondate2 BETWEEN 20130601 AND 20131031 AND
 event.siteid = 1
AND action.typeid = 1
;
+ ------------- +
| actionid      |
+ ------------- +
| 1             |
| 3             |
| 5             |
+ ------------- +

あなたの意図があなたの質問に表示されるクエリを最適化することである場合は、上記のクエリを使用してください。これがあなたの質問に対する答えです。

ただし、期待される結果についてのコメントを見ると、質問のクエリはおそらく間違っているようです。期待される結果が得られません。

まあ、しかし、クエリが何を与えるべきかはまだ不明です? 多くの可能性がありますが、以下にいくつかを示します。

action.actionidすべてをでリストする必要があるtypeid = 1が、そのようなレコードのみをリストする必要がある場合は、同じおよび... を持つレコードが存在する場合は、以下のクエリ (デモの 3 番目のクエリ) を使用します。eventidtypeid = 2

SELECT a.actionid 
FROM
  ACTION a
  INNER JOIN EVENT e
    ON a.eventid = e.eventid 
WHERE -- actiondate2 BETWEEN 20130601 AND 20131031 AND
  EXISTS ( SELECT 1 FROM action a1
              WHERE a1.eventid = a.eventid
              AND a1.typeid = 2
         ) 
   AND e.siteid = 1
   AND a.typeid = 1
;

+ ------------- +
| actionid      |
+ ------------- +
| 1             |
| 3             |
+ ------------- +

このクエリではEXISTS、代わりに演算子を使用していますCOUNT()- 同じレコードが存在するという情報が必要な場合、それらすべてをカウントする必要はありません! count はすべてのレコードを読み取る必要があり、EXISTS条件を満たす最初のレコードが見つかった場合はテーブルの読み取りを停止します。したがってEXISTS、通常は よりも高速ですCOUNT()

すべてaction.actionidtypeid = 1で一覧表示し、対応するレコードが存在する情報も表示する必要がある場合typeid = 2は、以下のクエリ (デモの 4 番目のクエリ) を使用します。

SELECT 
  a.actionid ,
  CASE WHEN EXISTS ( SELECT 1 FROM action a1
              WHERE a1.eventid = a.eventid
              AND a1.typeid = 2
         ) 
       THEN 'typeid=2 EXISTS'
       ELSE 'typeid=2 DOESN''T EXIST'
  END typeid2_exist
FROM
  ACTION a
  INNER JOIN EVENT e
    ON a.eventid = e.eventid 
WHERE -- actiondate2 BETWEEN 20130601 AND 20131031 AND
   e.siteid = 1
   AND a.typeid = 1
;
+ ------------- + ---------------------- +
| actionid      | typeid2_exist          |
+ ------------- + ---------------------- +
| 1             | typeid=2 EXISTS        |
| 3             | typeid=2 EXISTS        |
| 5             | typeid=2 DOESN'T EXIST |
+ ------------- + ---------------------- +

ただし、対応するレコードを - でカウントする必要がある場合はtypeid = 2、次のクエリが役立ちます (デモの 5 番目のクエリ)。

SELECT 
  a.actionid ,
  ( SELECT count(*) FROM action a1
              WHERE a1.eventid = a.eventid
              AND a1.typeid = 2
   ) typeid2_count
FROM
  ACTION a
  INNER JOIN EVENT e
    ON a.eventid = e.eventid 
WHERE -- actiondate2 BETWEEN 20130601 AND 20131031 AND
   e.siteid = 1
   AND a.typeid = 1
;
+ ------------- + ------------------ +
| actionid      | typeid2_count      |
+ ------------- + ------------------ +
| 1             | 1                  |
| 3             | 1                  |
| 5             | 0                  |
+ ------------- + ------------------ +

上記のクエリのいずれも要件を満たしていない場合は、(デモのサンプル データに基づいて) クエリが返す必要がある結果を示してください。これは、このフォーラムの誰かが要件をすべて満たす適切なクエリを作成するのに役立ちます。

次に、すべての期待を満たす適切なクエリを認識したら、そのパフォーマンスの最適化を開始できます。

于 2013-10-16T20:06:53.013 に答える