使用IN和GROUP BY运行MySQL Query非常慢

时间:2012-11-27 01:18:45

标签: mysql sql performance greatest-n-per-group

我正在尝试构建一个页面,其中显示了成员已收到的消息列表。我提出了这个mySQL查询,但运行速度非常慢。执行它至少需要10秒钟。

SELECT senderid,
       receiverid
FROM   messages
WHERE  ( receiverid, sentdate ) IN (SELECT receiverid,
                                           Max(sentdate)
                                    FROM   messages
                                    WHERE  receiverid = '1'
                                    GROUP  BY senderid)
ORDER  BY sentdate DESC 

这是我正在使用的数据库:

`autoID` mediumint(11) unsigned NOT NULL AUTO_INCREMENT
`senderID` mediumint(11) unsigned DEFAULT '0'
`receiverID` mediumint(11) unsigned DEFAULT '0'
`sentDate` datetime DEFAULT '0000-00-00 00:00:00'
`message` longtext
PRIMARY KEY (`autoID`)
KEY `receiverID` (`receiverID`)
KEY `senderID` (`senderID`)

数据库只有150,000个条目。我正在运行我自己的专用服务器,只有mySQL数据库。

非常感谢任何帮助。

G-Nugget,我在sentDate上添加了一个索引但没有加速。这是EXPLAIN(对不起,显示方式。不知道我还能怎么做):

ID:1个
SELECT_TYPE:PRIMARY
表:消息
类型:ALL
possible_keys:空
键:空
key_len:空
裁判:空
行:149433个
额外:使用在哪里;使用filesort

ID:2
select_type:DEPENDENT SUBQUERY
表:消息
类型:REF
possible_keys:receiverID
关键:receiverID
key_len:4
裁判:常量
行:20个
额外:使用在哪里;使用临时;使用filesort

2 个答案:

答案 0 :(得分:1)

这个查询产生你提到的结果集怎么样?

SELECT m.senderid,
       m.receiverid
  FROM messages m
  JOIN (
            SELECT  max(autoID) autoID, 
                    receiverID, SenderID
              FROM  messages
          GROUP BY  receiverId, SenderID
       ) X on m.autoID = x.AutoId
  WHERE m.receiverId = '1'
  ORDER BY m.autoID desc

这利用了autoID和sentdate很可能随着时间的推移单调递增的假设。它为每个不同的发送方/接收方对之间的最新消息提取ID,然后使用这些ID选择要显示的消息表的子集。

答案 1 :(得分:0)

在MySQL中,in的子查询无法正确优化。您的查询有点复杂。我认为这是编写查询的有效方式:

SELECT senderid,
       receiverid
FROM   messages m
WHERE  m.receiverid = '1' and
       exists (SELECT 1
               FROM   messages m1
               WHERE  m1.receiverid = '1'
               GROUP  BY m1.senderid
               having max(sentdate) =  m.sentdate)
ORDER  BY sentdate DESC 

您的查询似乎正在尝试将每次发送的最新消息发送到“1”。更简单的版本可能是:

select senderid, receiverid
from messages m
where m.receiverid = '1'

也就是说,每个senderid都将包含在您的原始查询中,因为它们的最新发送日期将与in条件匹配。您可以让两个发件人具有完全相同的日期和时间。是否需要显示这样的副本?