优化嵌套查询

时间:2013-07-26 18:38:26

标签: mysql sql optimization nested-query

我需要帮助优化下面的查询。我有桌子pt_votes有30 + k记录,每张投票(-1或1)保存照片,我想选择所有照片和他们的投票总和,所以我有如下所示的查询,但它需要大约9秒执行。我如何优化它?

 SELECT *, ifnull((SELECT SUM(vote) FROM pt_votes vo WHERE vo.pID = ph.pID),0) points,
                        (SELECT CONCAT(name, " ", surname) FROM pt_users us WHERE us.uID = ph.uID) name_surname
                    FROM pt_photos ph
                    WHERE 1

5 个答案:

答案 0 :(得分:0)

它没有以任何方式进行测试,但请试着看看这是否有帮助

SELECT *, SUM(ifnull(vo.vote,0)) points, CONCAT(us.name, " ", us.surname) name_surname
FROM pt_photos ph
LEFT JOIN pt_votes vo ON vo.pID = ph.pID
JOIN pt_users us ON us.uID = ph.uID

答案 1 :(得分:0)

使用JOIN,而不是相关的子查询。

SELECT ph.*,
       IFNULL(SUM(vo.vote), 0) points,
       CONCAT(us.name, " ", us.surname) name_surname
FROM photos ph
LEFT JOIN pt_votes vo ON ph.pId = vo.pID
INNER JOIN pt_users us ON us.uID = ph.uID
GROUP BY ph.uID

据我所知,不需要WHERE 1子句来选择所有行。只需省略WHERE子句。

答案 2 :(得分:0)

由于子查询的执行次数,相关子查询会对大型集合进行调光查询。

这是一个应该表现更好的替代方案:

SELECT ph.*
     , IFNULL(vs.points,0) AS points
     , CONCAT(us.name," ",us.surname) AS name_surname
  FROM pt_photos ph
  LEFT
  JOIN ( SELECT vo.pID
              , SUM(vo.vote) AS points
           FROM pt_votes vo
          GROUP BY vo.pID
       ) vs
    ON vs.pID = ph.pID
  LEFT
  JOIN pt_users us 
    ON us.uID = ph.uID
 WHERE 1

pt_votes上合适的索引(理想情况下是覆盖索引)将改善pt_votes (pID, vote)上GROUP BY ...的性能。

我将假设uID是pt_users的pirmary键。

答案 3 :(得分:0)

我会尝试将第三个选择重写为内连接,并可能在输出结果时将concat函数移动到。这是一个t-sql解决方案,但它应该足够相似:

select ph.*, 
concat(pu.name, " ", pu.surname) as name_surname,
isnull((select sum(vote) from pt_votes vo where vo.pid = ph.pid),0) as points
from pt_photos ph
inner join pt_users pu on ph.uid = pu.uid

你也可以对pt_votes表进行左连接以获得总和,但是你必须使用'group by'子句来使它全部正常工作,这对于处理时间来说可能是值得的。

答案 4 :(得分:0)

这里最大的效率杀手是相关的子查询:

(SELECT CONCAT(name, " ", surname)
  FROM pt_users us
  WHERE us.uID = ph.uID) name_surname

......和:

ifnull((SELECT SUM(vote)
  FROM pt_votes vo
  WHERE vo.pID = ph.pID),0) points,

对于使其超过WHERE子句的每一行,每个都会运行一次。

要消除您需要加入pt_votespt_users表的相关子查询。另外,因为你需要总结投票GROUP BY,这意味着你真的需要摆脱评论中已经建议的SELECT *。< / p>

查询看起来像这样。当您确定需要哪些pt_photos列时,请务必将其添加到GROUP BY列表中:

SELECT
  pt_photos.pID,
  pt_photos.uID,
  pt_photos.this,
  pt_photos.that,
  CONCAT(pt_users.name, ' ', pt_users.surname) AS name_surname,
  IFNULL(SUM(pt_votes.vote), 0) AS points
FROM pt_photos
JOIN pt_users ON pt_photos.uID = pt_users.uID
LEFT JOIN pt_votes ON pt_photos.pID = pt_votes.pID
WHERE 1
GROUP BY
  pt_photos.pID,
  pt_photos.uID,
  pt_photos.this,
  pt_photos.that

如果您的查询确实WHERE 1子句,则可以删除它。