Mysql 优化嵌套查询

Mysql 优化嵌套查询,mysql,sql,optimization,nested-query,Mysql,Sql,Optimization,Nested Query,我需要帮助优化下面的查询。我有30+k记录的表pt_投票,其中保存了照片的每个投票-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

我需要帮助优化下面的查询。我有30+k记录的表pt_投票,其中保存了照片的每个投票-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

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

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

使用联接,而不是相关子查询

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子句。

由于子查询的执行次数,相关子查询在大型集合上会使查询变暗

以下是一个性能更好的替代方案:

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_投票的覆盖指数)将通过以下方式改善集团的绩效:。。。在pt_投票中,投票


我将假设uID是pt_用户的pirmary键。

我将尝试将第三个select重写为内部联接,并可能在输出结果时将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”子句以使其全部正常工作,这在处理时间上可能是值得的。

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

(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_投票和pt_用户表。另外,因为你要对投票进行汇总,你需要分组,这意味着你真的需要摆脱评论中已经建议的选择

查询将如下所示。确定需要哪些pt_photos列时,请确保将其添加到GROUP BY列表中:


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

您能用特定字段替换*吗?当您对查询进行解释时会发生什么情况。。是否有任何键可以创建/优化?是否可以添加表结构,如果nullselect SUMvote FROM pt_vots vo WHERE vo.pID=ph.pID,0可能会有帮助,我怀疑这可以替换为左连接,这将加快速度
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