以下mysql查询需要40秒才能执行,而且太多了
我该如何优化呢?
SELECT
downloads.*,
COUNT(DISTINCT comment.id) AS commentsNum,
AVG(users_votes.rate) AS score,
COUNT(DISTINCT users_votes.id) AS rateNum,
COUNT(DISTINCT users_download.id) AS downloadsNum
FROM downloads
LEFT JOIN (
SELECT * FROM comment WHERE type='download'
) comment ON downloads.id = comment.typeID
LEFT JOIN (
SELECT * FROM users_votes WHERE section='download' AND rate>0
) users_votes ON downloads.id = users_votes.voteID
LEFT JOIN (
SELECT id,downloadID FROM users_download GROUP BY userID,downloadID
) users_download ON downloads.id = users_download.downloadID
GROUP BY downloads.id
EXPLAIN 的结果:
答案 0 :(得分:1)
您应该通过download_id将结果集分组到连接中。
SELECT
downloads.*,
comment.commentsNum,
users_votes.AvgScore,
users_votes.rateNum,
users_download.downloadsNum
FROM downloads
LEFT JOIN (
SELECT TypeID,COUNT(*) AS commentsNum FROM comment WHERE type='download' GROUP BY TypeID
) comment ON downloads.id = comment.typeID
LEFT JOIN (
SELECT voteID,AVG(rate) AS AvgScore,COUNT(*) AS rateNum FROM users_votes WHERE section='download' AND rate > 0 GROUP BY voteID
) users_votes ON downloads.id = users_votes.voteID
LEFT JOIN (
SELECT downloadID,COUNT(userID) AS downloadsNum FROM users_download GROUP BY downloadID
) users_download ON downloads.id = users_download.downloadID
答案 1 :(得分:1)
从您的解释来看,users_download
表似乎是罪魁祸首。该查询被强制扫描该表中的100k行,我猜这是因为GROUP BY
与未命中索引相结合。
“使用filesort”是一个警告标志,因为它必须将表的一部分写入磁盘才能进行排序(可能再次进行分组)。众所周知,磁盘非常慢。
我不确定您要完全尝试做什么,但GROUP BY
通常很昂贵,因此如果您可以在不使用GROUP BY
的情况下重写查询,那么这可能对性能有利。否则,尝试创建一个索引,可以帮助MySQL找到正确的行,而无需扫描表格的这么大部分。
答案 2 :(得分:0)
这是优化查询
为什么这个查询执行得非常快?
但旧查询执行速度很慢?
专家程序员分析:)
SELECT
downloads.*,
comment.commentsNum AS commentsNum,
users_votes.AvgScore AS score,
users_votes.rateNum AS rateNum,
users_download.downloadsNum AS downloadsNum
FROM downloads
LEFT JOIN (
SELECT typeID,COUNT(id) AS commentsNum FROM comment WHERE type='download' GROUP BY typeID
) comment ON downloads.id = comment.typeID
LEFT JOIN (
SELECT voteID, AVG(rate) AS AvgScore,COUNT(id) AS rateNum FROM users_votes WHERE section='download' AND rate > 0 GROUP BY voteID
) users_votes ON downloads.id = users_votes.voteID
LEFT JOIN (
SELECT id,downloadID,COUNT(id) AS downloadsNum FROM users_download WHERE id IN (SELECT MIN(id) FROM users_download GROUP BY userID,downloadID) GROUP BY downloadID ORDER BY downloadID
)
users_download ON downloads.id = users_download.downloadID