繁体   English   中英

优化缓慢的mysql查询

[英]optimizing a slow mysql query

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

在此处输入图片说明

您应通过download_id将结果集归为join。

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 

从您的解释来看, users_download表似乎是罪魁祸首。 该查询被迫从该表中扫描10万行,我猜这是由于GROUP BY与未命中索引相结合。

“使用文件排序”是一个警告信号,因为它必须将表的某些部分写入磁盘才能进行排序(可能是再次分组)。 众所周知,磁盘非常慢。

我不确定您要尝试做的是什么,但是GROUP BY通常很昂贵,因此,如果您不使用GROUP BY即可重写查询,则可能会提高性能。 否则,请尝试创建一个索引,该索引可以帮助MySQL查找正确的行而无需扫描表的大部分内容。

这是优化的查询

为什么这个查询执行得很快?

但是旧查询执行得很慢?

专家程序员分析:)

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 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM