优化慢速mysql查询

时间:2014-10-13 12:03:00

标签: mysql sql select join subquery

以下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 的结果:

enter image description here

3 个答案:

答案 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