2012-11-27 109 views
2

我试图构建一个页面,其中显示了一个成员收到的消息列表。我想出了这个mySQL查询,但运行速度非常慢。执行它至少需要10秒钟的时间。使用IN和GROUP BY运行MySQL查询非常缓慢

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`)

的数据库只有15万项。我正在运行我自己的专用服务器,只有它的mySQL数据库。

任何帮助是极大的赞赏。

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

ID:1
SELECT_TYPE:PRIMARY
表:消息
类型:
possible_keys:空
键:空
key_len:空
裁判:空
行:149433
额外:使用哪里;使用文件排序

ID:2
SELECT_TYPE:DEPENDENT SUBQUERY
表:消息
类型:REF
possible_keys:receiverID
键:receiverID
key_len:4
REF:常量
行:20
额外:使用where;使用临时;使用filesort

+1

可能出现[获取具有列最大值的行](http:// stackoverflow。com/questions/121387/fetch-the-row-which-has-the-max-value-for-a-column) –

+0

请发布查询的'EXPLAIN'。看起来你可以从'sentdate'的索引中受益。 –

+1

嘿,伙计们,这是一个mySQL问题。投票结束它的人声称这是与甲骨文问题重复。不是! –

回答

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和senddate最有可能随着时间流逝单调增加的假设。它为每个不同的发送者/接收者之间的最近消息提供ID,然后使用这些ID挑选要显示的消息表的子集。

+0

我的想法和你一样......但是,将WHERE子句添加到INNER select中也是如此。只收集ReceiverID ='1'的消息与所有可能的消息接收者。没有订单,因为它会为接收方返回一个记录......最后一个。 – DRapp

+0

Ollie Jones您的查询导致在<1秒内加载页面!绝对真棒。接下来的@DRAP建议使页面更快。你们好棒!!非常感谢!!!! –

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将被包含在您的原始查询,因为他们最近sentdate将匹配in条件。你可以有两个发送者完全相同的日期和时间。是否需要显示这样的重复项?

+0

谢谢戈登的回答。由于Ollie的回答工作得很好,我就跟着去了。尽管如此,我非常感谢你的帮助。 –

+0

@JakobHerrmann。 。 。他的回答可能对你的问题更好。当我开始回答时,我没有意识到子查询中有一组。但是,第二个查询是否也回答了您的问题,或者我错过了什么? –