2012-11-27 149 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。 。 。他的回答可能對你的問題更好。當我開始回答時,我沒有意識到子查詢中有一組。但是,第二個查詢是否也回答了您的問題,或者我錯過了什麼? –