MySQL查询优化 - 内部查询

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)

das*_*ash 3

您始终可以使用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 来看看现在有什么区别(编辑,因为我们从上面的评论中已经知道了!)