This is the whole query...
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
If...
SELECT url FROM show_medias WHERE show_id = s.id AND is_primary = 1
(0.0004 sec)
And...
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)
Is there an obvious reason....
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
is taking 5.7245 sec
?
EXPLAIN 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
You can always use EXPLAIN or EXPLAIN EXTENDED to see what MySql is doing with a query
You could also write your query a slightly different way, have you tried the following?
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
It would be interesting to see what the effect of that is. I would expect it to be faster as, at the moment, I think MySql will be running inner query 1 for each show you have (so that one query will be run many times. A join should be more efficient.)
Replace the INNER JOIN with a LEFT JOIN if you want all shows that don't have a row in show_medias.
EDIT:
I'll take a look at your EXPLAIN EXTENDED shortly, I also wonder if you want to try the following; it removes all of the subqueries:
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
(It would also be good to see the EXPLAIN EXTENDED on these - you could add it to the comments for this one).
Further EDIT:
On your EXPLAIN EXTENDED (a good start on how to read these is here)
The USING FILESORT and USING TEMPORARY are both key indicators. Hopefully, the second query I recommend should remove any TEMPORARY tables (in the subquery). Try then leaving the ORDER BY off to see if that makes a difference (and we can add that to the findings so far :-)
I can also see that the query is potentially missing out on a lot of index lookups; all of your id columns are prime candidates for index matches (with the usual index caveats). I'd also try adding those indexes and then running EXPLAIN EXTENDED again to see what the difference is now (EDIT as we already know from your comment above!)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With