2012-01-08 19 views
5

これは全体のクエリです...MySQLのクエリの最適化 - 内部クエリ

SELECT s.*, (SELECT url FROM show_medias WHERE show_id = s.id AND is_primary = 1) AS media_url 
FROM (shows As s) 
WHERE `s`.`id` IN (
SELECT DISTINCT st.show_id 
FROM show_time_schedules AS sts 
LEFT JOIN show_times AS st ON st.id = sts.show_time_id 
WHERE sts.schedule_date BETWEEN CAST('2012-01-10' AS date) AND CAST('2012-01-14' AS date) 
) 
AND `s`.`is_active` = 1 
ORDER BY s.name asc 

もし...

SELECT url FROM show_medias WHERE show_id = s.id AND is_primary = 1 
(0.0004 sec) 

そして...

SELECT DISTINCT st.show_id 
FROM show_time_schedules AS sts 
LEFT JOIN show_times AS st ON st.id = sts.show_time_id 
WHERE sts.schedule_date BETWEEN CAST('2012-01-10' AS date) AND CAST('2012-01-14' AS date) 
(0.0061 sec) 

が明らかにあります理由....

SELECT s.*, (inner query 1) AS media_url 
FROM (shows As s) 
WHERE `s`.`id` IN (inner query 2) 
AND `s`.`is_active` = 1 
ORDER BY s.name asc 

5.7245 secですか?

は、あなたはいつもあなたはまた、あなたのクエリ若干異なる方法を書くことができますが、以下のことを試してみました?MySQLは、クエリ

でやっているものを見るためにEXPLAIN or EXPLAIN EXTENDEDを使用することができますEXTENDED

id select_type   table  type possible_keys key  key_len ref      rows filtered Extra 
1 PRIMARY    s   ALL  NULL   NULL NULL NULL     151  100.00  Using where; Using filesort 
3 DEPENDENT SUBQUERY sts   ALL  NULL   NULL NULL NULL     26290 100.00  Using where; Using temporary 
3 DEPENDENT SUBQUERY st   eq_ref PRIMARY   PRIMARY 4  bvcdb.sts.show_time_id 1  100.00  Using where 
2 DEPENDENT SUBQUERY show_medias ALL  NULL   NULL NULL NULL     159  100.00  Using where 
+0

興味深いことに、あなたはあなたがあなたにウルでショーをしたいかどうかによって(INNER、LEFT)あなたの選択リストでサブクエリを実行するのではなく、show_medias.show_id = s.idでshow_mediasに参加していますか?私はそれを見ることに興味があるだろう。クエリのEXPLAINには何もありませんか? – dash

+0

@dashこれまでのところ、あなたの助けを借りてくれてありがとう、 'EXPLAIN EXTENDED'を追加しました。あなたの提案されたクエリは、6.x秒のパフォーマンスを少し上回らなければほぼ同じ結果を出しました。 – jondavidjohn

+0

テーブルにどのようなインデックスがあるのか​​知っていますか?特に、show、show_time_schedules、show_times、およびshow_mediasのクエリインデックスに使用されているidカラムはどれですか? – dash

答えて

3

をEXPLAIN

SELECT  s.*, 
       sm.url AS media_url 
FROM   shows AS s 
INNER JOIN show_medias AS sm ON s.id = SM.show_id 
WHERE `s`.`id` IN ( 
         SELECT DISTINCT st.show_id 
         FROM show_time_schedules AS sts 
         LEFT JOIN show_times AS st ON st.id = sts.show_time_id 
         WHERE sts.schedule_date BETWEEN CAST('2012-01-10' AS date) AND CAST('2012-01-14' AS date) 
         ) 
AND   `s`.`is_active` = 1 
AND   sm.is_primary = 1 
ORDER BY  s.name asc 

これは何の効果があるのか​​興味深いでしょう。現時点ではMySqlはあなたが持っている各ショーの内部クエリー1を実行していると思いますので(1つのクエリーが何度も実行されるようにしてください)

show_mediasに行がないすべての番組が必要な場合は、INNER JOINをLEFT JOINに置き換えます。

EDIT:あなたは次のことを試してみたい場合は

私はあなたのすぐEXTENDED EXPLAINを見てみましょう、私も疑問に思います。それは、サブクエリのすべてを削除します。

SELECT  DISTINCT s.*, 
         sm.url AS media_url 
FROM     shows AS s 
INNER JOIN    show_medias AS sm ON s.id = SM.show_id 
INNER JOIN    show_times AS st ON (s.id = st.show_id) 
RIGHT JOIN    show_time_schedules AS sts ON (st.id = sts.show_time_id) 

WHERE     `s`.`is_active` = 1 
AND     sm.is_primary = 1 
AND     sts.schedule_date BETWEEN CAST('2012-01-10' AS date) AND CAST('2012-01-14' AS date) 
ORDER BY    s.name asc 

(また、これらの拡張EXPLAIN見ていいだろう - あなたはこの1つのコメントにそれを追加することもできます)。

さらにEDIT:あなたのEXTENDED EXPLAIN(a good start on how to read these is here

filesortレコードを使用してTEMPORARYを使用すると、両方の主要な指標です。うまくいけば、私が推薦する2番目のクエリは、サブクエリ内のTEMPORARYテーブルを削除する必要があります。 ORDER BYをオフにして、違いがあるかどうかを確認してください(そしてこれまでの所見にこれを追加することができます:-)

多くのインデックスルックアップでクエリが欠落している可能性があります。すべてのid列は、インデックス一致のための主要な候補です(通常index caveats)。私はまた、これらのインデックスを追加して、次にEXPLAIN EXTENDEDを実行して、違いが現在何かを確認したいと思います。ここでは)

2

はCTE-ソリューションを付属しています(私の悪い、mysqlはCTEのを持っていませんが、問題は、あまりにも一般的なもので)

WITH RECURSIVE tree AS (
    SELECT t0.id 
     , t0.study_start_time 
     , t0.study_end_time 
    FROM tab t0 
    WHERE NOT EXISTS (SELECT * FROM tab nx 
      WHERE nx.id=t0.id 
      AND nx.study_end_time = t0.study_start_time 
      ) 
    UNION 
    SELECT tt.id 
     ,tt.study_start_time 
     ,t1.study_end_time 
    FROM tab t1 
    JOIN tree tt ON t1.id=tt.id 
       AND t1.study_start_time = tt.study_end_time 
    ) 
SELECT * FROM tree 
WHERE NOT EXISTS (SELECT * FROM tab nx 
       WHERE nx.id=tree.id 
       AND tree.study_end_time = nx.study_start_time 
       ) 
ORDER BY id 
    ; 

結果:

CREATE TABLE 
INSERT 0 15 
    id | study_start_time | study_end_time 
------+------------------+---------------- 
1234 |    168 |   480 
2345 |    175 |   233 
2345 |    400 |   425 
4567 |    200 |   225 
4567 |    250 |   289 
4567 |    300 |   310 
4567 |    320 |   340 
4567 |    360 |   390 
(8 rows) 

クエリプラン(追加後明らかなPKとインデックス):

DROP TABLE 
NOTICE: CREATE TABLE/PRIMARY KEY will create implicit index "tab_pkey" for table "tab" 
CREATE TABLE 
CREATE INDEX 
INSERT 0 15 

                   QUERY PLAN                 
------------------------------------------------------------------------------------------------------------------------------------------- 
Merge Anti Join (cost=16209.59..16292.13 rows=6386 width=12) (actual time=0.189..0.193 rows=8 loops=1) 
    Merge Cond: ((tree.id = nx.id) AND (tree.study_end_time = nx.study_start_time)) 
    CTE tree 
    -> Recursive Union (cost=0.00..15348.09 rows=8515 width=12) (actual time=0.022..0.136 rows=15 loops=1) 
      -> Merge Anti Join (cost=0.00..175.04 rows=1455 width=12) (actual time=0.019..0.041 rows=8 loops=1) 
       Merge Cond: ((t0.id = nx.id) AND (t0.study_start_time = nx.study_end_time)) 
       -> Index Scan using tab_pkey on tab t0 (cost=0.00..77.35 rows=1940 width=12) (actual time=0.010..0.018 rows=15 loops=1) 
       -> Index Scan using sssss on tab nx (cost=0.00..77.35 rows=1940 width=8) (actual time=0.003..0.008 rows=14 loops=1) 
      -> Merge Join (cost=1297.04..1500.28 rows=706 width=12) (actual time=0.010..0.012 rows=1 loops=6) 
       Merge Cond: ((t1.id = tt.id) AND (t1.study_start_time = tt.study_end_time)) 
       -> Index Scan using tab_pkey on tab t1 (cost=0.00..77.35 rows=1940 width=12) (actual time=0.001..0.004 rows=9 loops=6) 
       -> Sort (cost=1297.04..1333.42 rows=14550 width=12) (actual time=0.006..0.006 rows=2 loops=6) 
         Sort Key: tt.id, tt.study_end_time 
         Sort Method: quicksort Memory: 25kB 
         -> WorkTable Scan on tree tt (cost=0.00..291.00 rows=14550 width=12) (actual time=0.000..0.001 rows=2 loops=6) 
    -> Sort (cost=726.15..747.44 rows=8515 width=12) (actual time=0.166..0.169 rows=15 loops=1) 
     Sort Key: tree.id, tree.study_end_time 
     Sort Method: quicksort Memory: 25kB 
     -> CTE Scan on tree (cost=0.00..170.30 rows=8515 width=12) (actual time=0.025..0.149 rows=15 loops=1) 
    -> Sort (cost=135.34..140.19 rows=1940 width=8) (actual time=0.018..0.018 rows=15 loops=1) 
     Sort Key: nx.id, nx.study_start_time 
     Sort Method: quicksort Memory: 25kB 
     -> Seq Scan on tab nx (cost=0.00..29.40 rows=1940 width=8) (actual time=0.003..0.004 rows=15 loops=1) 
Total runtime: 0.454 ms 
(24 rows) 
+0

MySQLはこれをサポートしていますか?それがあれば、それは素晴らしいでしょう!しかし、私は間違った質問を見たかもしれないと思う;-) – dash

+0

いいえ、それは、ごめんなさい。私はmysqlタグを見なかったし、後で追加した。 CTEはリンクされたリストを追跡するのに最適です(IAGは基本的にリンクされたリストなので、CTEは私の膝のようなものです)。楽しみのためだけにクエリプランを追加します。 。 – wildplasser

+0

おっと、申し訳ありませんが、私は間違った項目に投稿しました - [ – wildplasser