2012-01-08 14 views
5

Ésta es toda la consulta ...Optimización de MySQL Query - consultas internas

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 

Si ...

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

Y ...

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) 

¿Existe una obvia razón ...

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 

está tomando 5.7245 sec?

explican EXTENDIDO

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

Fuera de interés, ¿ha mirado el rendimiento por (INTERIOR, IZQUIERDO dependiendo de si solo desea mostrar con su l o no) ¿ÚNETE a show_medias en show_medias.show_id = s.id en lugar de hacer la subconsulta en su lista de selección? Me interesaría ver eso. ¿Algo en EXPLAIN para la consulta? – dash

+0

@dash muchas gracias por su ayuda hasta ahora, agregó el 'EXPLAIN EXTENDED', y su consulta sugerida arrojó casi el mismo rendimiento si no un poco más largo de 6.x segundos. – jondavidjohn

+0

¿Sabes qué índices tienes en tus tablas? En particular, ¿alguna de las columnas de Id. Utilizadas en su índice de consulta está en shows, show_time_schedules, show_times y show_medias? – dash

Respuesta

3

Siempre se puede usar EXPLAIN or EXPLAIN EXTENDED para ver lo que MySQL está haciendo con una consulta

También puede escribir su consulta una manera ligeramente diferente, ¿ha intentado el siguiente?

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 

Sería interesante ver cuál es el efecto de eso. Esperaría que fuera más rápido ya que, en este momento, creo que MySql ejecutará la consulta interna 1 para cada programa que tenga (de modo que una consulta se ejecutará muchas veces. Una unión debería ser más eficiente.)

Reemplace el INNER JOIN con un LEFT JOIN si desea que todos los programas que no tengan una fila se muestren en show_medias.

EDIT:

voy a echar un vistazo a su EXPLICAR amplió poco tiempo, también me pregunto si quieres probar lo siguiente; que elimina todas las subconsultas:

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 

(También sería bueno ver que la explican ampliadas sobre estos - se podría añadir a los comentarios para éste).

hacer otras modificaciones:

En su EXPLICAR EXTENDIDO (a good start on how to read these is here)

La USO DE USO filesort y temporales son ambos indicadores clave. Con suerte, la segunda consulta que recomiendo debería eliminar cualquier tabla TEMPORAL (en la subconsulta). Intenta luego dejar el ORDER BY apagado para ver si eso hace la diferencia (y podemos agregar eso a los hallazgos hasta el momento :-)

También puedo ver que la consulta se puede perder en muchas búsquedas de índices; todas sus columnas de identificación son las principales candidatas para las coincidencias de índice (con el index caveats habitual). También intentaré agregar esos índices y luego ejecutar EXPLAIN EXTENDED de nuevo para ver cuál es la diferencia ahora (¡EDITAR como ya sabemos por tu comentario anterior!)

2

Aquí viene la CTE-solución: (mi mal, MySQL no tiene CTE, pero el problema es demasiado genérico)

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 
    ; 

Resultados:

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) 

plan de consulta (después de añadir PK e índice obvio):

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

¿Soporta MySQL esto? Si lo hace, ¡eso sería genial! Sin embargo, creo que es posible que haya mirado la pregunta incorrecta ;-) – dash

+0

No, no lo hace, lo siento. No vi la etiqueta mysql o se agregó más tarde. Los CTE son una gran manera de perseguir listas enlazadas (por eso retiré islas y brechas, las IAG son básicamente listas vinculadas, por lo que los CTE son como un reflejo de rodilla para mí) Agregaré un plan de consulta, solo por diversión. .. – wildplasser

+0

Vaya, disculpe, publiqué en el artículo incorrecto; - [ – wildplasser