jon*_*ohn 5 mysql sql optimization
这是整个查询......
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
Run Code Online (Sandbox Code Playgroud)
如果...
SELECT url FROM show_medias WHERE show_id = s.id AND is_primary = 1
(0.0004 sec)
Run Code Online (Sandbox Code Playgroud)
和...
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)
Run Code Online (Sandbox Code Playgroud)
有明显的原因......
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
Run Code Online (Sandbox Code Playgroud)
正在服用5.7245 sec?
扩展说明
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
Run Code Online (Sandbox Code Playgroud)
您始终可以使用EXPLAIN 或 EXPLAIN EXTENDED来查看 MySql 对查询执行的操作
您也可以以稍微不同的方式编写查询,您尝试过以下方法吗?
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
Run Code Online (Sandbox Code Playgroud)
看看这会产生什么效果会很有趣。我希望它会更快,因为目前,我认为 MySql 将为您拥有的每个节目运行内部查询 1(这样一个查询将运行多次。联接应该更有效。)
如果您希望所有节目在 show_medias 中没有行,请将 INNER JOIN 替换为 LEFT JOIN。
编辑:
我很快就会看一下您的 EXPLAIN EXTENDED,我也想知道您是否想尝试以下操作;它删除所有子查询:
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
Run Code Online (Sandbox Code Playgroud)
(如果能看到这些内容的扩展说明也很好 - 您可以将其添加到此评论中)。
进一步编辑:
关于您的 EXPLAIN EXTENDED(这里是如何阅读这些内容的良好开端)
USING FILESORT 和 USING TEMPORARY 都是关键指标。希望我建议的第二个查询应该删除所有临时表(在子查询中)。然后尝试将 ORDER BY 关闭,看看这是否会产生影响(我们可以将其添加到迄今为止的发现中:-)
我还可以看到该查询可能会错过很多索引查找;您的所有 id 列都是索引匹配的主要候选者(带有通常的索引警告)。我还尝试添加这些索引,然后再次运行 EXPLAIN EXTENDED 来看看现在有什么区别(编辑,因为我们从上面的评论中已经知道了!)