2012-01-08 14 views
5

Jest cała kwerendy ...optymalizacji zapytań MySQL - wewnętrzne zapytań

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 

Jeśli ...

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

I ...

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) 

Czy istnieje oczywista powód ....

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 

bierze 5.7245 sec?

wytłumaczyć ROZSZERZONY

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

Ciekawe, czy spojrzał na wydajność przez (INNER, LEFT w zależności od tego, czy chcesz tylko pokazy z ur l czy nie) ŁĄCZENIE do show_medias w show_medias.show_id = s.id zamiast wykonywania podkwerendy na liście select? Byłbym zainteresowany widząc to. Coś w EXPLAIN dla zapytania? – dash

+0

@dash bardzo dziękuję za pomoc, dodano "EXPLAIN EXTENDED", a Twoje sugerowane zapytanie dawało prawie takie same, jeśli nie trochę więcej, niż 6x sekund. – jondavidjohn

+0

Czy wiesz, jakie indeksy masz na swoich stołach? W szczególności, czy którekolwiek z kolumn identyfikatora są używane w indeksie zapytań w programach, show_time_schedules, show_times i show_medias? – dash

Odpowiedz

3

zawsze można użyć EXPLAIN or EXPLAIN EXTENDED zobaczyć co MySQL robi z kwerendy

Można również napisać zapytanie nieco inny sposób, czy próbowałem następujące?

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 

Byłoby interesujące zobaczyć, jaki jest tego efekt. Spodziewałbym się, że będzie on szybszy, ponieważ w tej chwili MySql będzie uruchamiał wewnętrzne zapytanie 1 dla każdego pokazu, który masz (tak, że jedno zapytanie będzie uruchamiane wiele razy. Łączenie powinno być bardziej wydajne.)

Zamień INNER JOIN LEFT JOIN, jeśli chcesz wszystkie pokazy, które nie mają wiersza w show_medias.

EDIT:

będę przyjrzeć wyjaśniania ROZSZERZONY krótko, ja też zastanawiam się, jeśli chcesz spróbować następujących; usuwa wszystkie podzapytania:

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 

(Byłoby również dobrze, aby zobaczyć wytłumaczyć ROZSZERZONY na nich - można go dodać do komentarzy na temat tego jednego).

Dalsze EDIT:

Na wyjaśniania ROZSZERZONY (a good start on how to read these is here)

Using filesort i stosując tymczasowe są zarówno kluczowych wskaźników. Mam nadzieję, że drugie zapytanie, które zalecam, powinno usunąć wszelkie tabele TYMCZASOWE (w podzapytaniu). Spróbuj następnie pozostawić ORDER BY, aby sprawdzić, czy to robi różnicę (i możemy dodać to do ustaleń do tej pory :-)

Widzę również, że kwerenda potencjalnie pomija wiele wyszukiwań indeksu; wszystkie twoje kolumny id są pierwszymi kandydatami do dopasowania indeksu (zwykle z index caveats). Chciałbym również spróbować dodać te indeksy, a następnie ponownie uruchomić EXPLAIN EXTENDED, aby zobaczyć, jaka jest teraz różnica (EDIT, jak już wiemy z powyższego komentarza!)

2

Nadchodzi CTE-rozwiązanie: (moja zła, mysql nie ma CTE, ale problem jest zbyt ogólne)

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 
    ; 

Wyniki:

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) 

planu kwerend (po dodaniu oczywiste PK i indeksu):

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

Czy MySQL obsługuje to? Jeśli tak, to byłoby genialne! Myślę jednak, że mogłeś spojrzeć na niewłaściwe pytanie ;-) – dash

+0

Nie, nie jest, przepraszam. Nie widziałem tagu mysql lub został dodany później. CTE to świetny sposób na ściganie połączonych list (dlatego ponownie zapisałem na wyspy i luki, IAG to w zasadzie powiązane listy, więc CTE są dla mnie jak odruch kolanowy) Dodam plan kwerend, tylko dla zabawy. .. – wildplasser

+0

Ups, przepraszam, wysłałem do niewłaściwego przedmiotu; - [ – wildplasser

Powiązane problemy