我需要帮助优化下面的查询。我有桌子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
答案 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_votes
和pt_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
子句,则可以删除它。