小编典典

MySQL查询优化-内部查询

sql

这就是整个查询…

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

如果…

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

和…

 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)

有明显的理由吗?

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

正在服用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

阅读 232

收藏
2021-04-22

共1个答案

小编典典

您可以始终使用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

看看效果如何会很有趣。我希望它会更快,因为目前,我认为MySql将为您拥有的每个节目运行内部查询1(这样一个查询将运行多次。联接应该更有效。)

如果希望所有show_medias中没有一行的节目,请用LEFT JOIN替换INNER 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

(也可以在这些内容上看到扩展的扩展-您可以将其添加到此注释的注释中)。

进一步编辑:

在您的扩展说明中(这里是如何阅读这些内容的良好开端

USING FILESORT和USING
TEMPORARY都是关键指标。希望我建议的第二个查询应该删除任何TEMPORARY表(在子查询中)。然后尝试关闭ORDER
BY以查看是否有区别(我们可以将其添加到到目前为止的发现中:-)

我还可以看到,很多索引查找都可能丢失查询;您所有的id列都是索引匹配的主要候选对象(具有常见的索引警告)。我还将尝试添加这些索引,然后再次运行EXPLAIN EXTENDED来查看现在的区别(编辑,正如我们从您上面的评论中已经知道的那样!)

2021-04-22