2012-01-08 25 views
5

Questo è l'intera query ...MySQL Query Optimization - query interne

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 

Se ...

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

E ...

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) 

v'è un evidente motivo ....

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 

sta prendendo 5.7245 sec?

spiegare 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

Per motivi di interesse, hai guardato l'esecuzione di (INTERO, A SINISTRA a seconda se vuoi mostrare solo con una Io o no) ISCRIVITI a show_medias su show_medias.show_id = s.id invece di fare la subquery nella tua lista di selezione? Sarei interessato a vederlo. Qualcosa in EXPLAIN per la query? – dash

+0

@dash grazie mille per il tuo aiuto finora, aggiunto 'EXPLAIN EXTENDED', e la tua query suggerita ha prodotto quasi la stessa prestazione se non un po 'più lunga 6.x secondi. – jondavidjohn

+0

Sai quali indici hai sui tuoi tavoli? In particolare, ci sono colonne id utilizzate nel tuo indice di query su show, show_time_schedules, show_times e show_medias? – dash

risposta

3

È sempre possibile utilizzare EXPLAIN or EXPLAIN EXTENDED per vedere cosa MySql sta facendo con una query

Si potrebbe anche scrivere la vostra richiesta un modo leggermente diverso, hai provato la seguente?

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 

Sarebbe interessante vedere quale sia l'effetto di ciò. Mi aspetto che sia più veloce perché, al momento, penso che MySql eseguirà la query interna 1 per ogni spettacolo che possiedi (in modo che una query venga eseguita più volte. Un join dovrebbe essere più efficiente)

Sostituisci INNER JOIN con LEFT JOIN se vuoi mostrare tutti gli show che non hanno una riga in show_medias.

EDIT:

mi prendo un'occhiata al tuo SPIEGARE esteso a breve, mi chiedo anche se si vuole provare il seguente; rimuove tutti i sottointerrogazioni:

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 

(Sarebbe anche bello vedere la spiegare estende su questi - si potrebbe aggiungere che ai commenti per questo).

Ulteriori EDIT:

Sul SPIEGARE EXTENDED (a good start on how to read these is here)

L'UTILIZZO FileSort e UTILIZZO temporanee sono entrambi gli indicatori chiave. Si spera che la seconda query che raccomando dovrebbe rimuovere qualsiasi tabella TEMPORARY (nella sottoquery). Prova quindi a lasciare l'ordine BY off per vedere se questo fa la differenza (e possiamo aggiungerlo ai risultati finora :-)

Posso anche vedere che la query è potenzialmente mancante su molte ricerche di indice; tutte le colonne ID sono i candidati migliori per le corrispondenze indice (con il solito index caveats). Cercherò anche di aggiungere quegli indici e quindi di eseguire EXPLAIN EXTENDED di nuovo per vedere qual è la differenza ora (EDIT come già sappiamo dal tuo commento qui sopra!)

2

Arriva il CTE-soluzione: (il mio male, mysql non ha CTE, ma il problema è troppo generico)

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 
    ; 

Risultati:

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) 

piano di query (dopo l'aggiunta ovvio PK e indice):

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 supporta questo? Se lo fa, sarebbe fantastico! Tuttavia, penso che potresti aver guardato alla domanda sbagliata ;-) – dash

+0

No, non è così, mi dispiace. Non ho visto il tag mysql o è stato aggiunto in seguito. I CTE sono un ottimo modo per inseguire le liste concatenate (è per questo che mi sono ricollocato in Islands-and-gaps, gli IAG sono fondamentalmente liste collegate, quindi le CTE sono come un riflesso del ginocchio per me) Aggiungerò un piano di query, solo per divertimento. .. – wildplasser

+0

Oops, mi dispiace, ho postato l'elemento sbagliato; - [ – wildplasser