0

我需要帮助优化下面的这个查询。我有 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
4

5 回答 5

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
于 2013-07-26T18:45:46.423 回答
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子句。

于 2013-07-26T18:47:19.437 回答
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 上的合适索引(理想情况下是覆盖索引)将提高 GROUP BY... 上的性能pt_votes (pID, vote)

我将假设 uID 是 pt_users 的 pirmary 键。

于 2013-07-26T18:48:45.337 回答
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”子句才能使其全部正常工作,这对于处理时间来说可能是值得的。

于 2013-07-26T18:53:30.730 回答
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 *需要像评论中已经建议的那样摆脱它。

查询看起来像这样。当您确定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子句,您可以删除它。

于 2013-07-26T18:55:31.063 回答