2014-10-30 84 views
-1

我需要加快此查詢列表最新消息。此查詢運行時間過長(例如,10秒...)如何加快這個MySQL查詢?最新消息查詢

SELECT datas.uid, 
     datas.message, 
     datas.date, 
     CONCAT(conv.first_name, ' ', conv.last_name) AS conversation_name 
FROM (SELECT m.message_id, 
       m.message, 
       IF (m.from_uid = 1, m.to_uid, m.from_uid) AS uid, 
       m.readed, 
       m.sended         AS `date` 
     FROM users u 
       LEFT JOIN messages m 
         ON m.from_uid = u.user_id 
     WHERE m.message_id IN (SELECT MAX(message_id) 
           FROM messages 
           WHERE to_uid = 1 
             OR from_uid = 1 
           GROUP BY LEAST(from_uid, to_uid), 
              GREATEST(from_uid, to_uid))) datas 
     LEFT JOIN users conv 
       ON conv.user_id = datas.uid 
ORDER BY datas.date DESC 
LIMIT 5 

此查詢使用2個表格(用戶和消息)。 表用戶:

  • USER_ID(伯,自動增量)
  • 登錄
  • 如first_name
  • 姓氏
  • ....

表MESSA GES:

  • MESSAGE_ID(伯,自動增量)
  • from_uid(發送方消息,參照表的用戶 - > USER_ID)
  • to_uid(接收器的消息,參照表的用戶 - > USER_ID)
  • sended(時間戳)
  • 消息(VARCHAR)

EDIT 我添加索引消息: - from_uid - to_uid - sended

,這是不效應...

+0

你對錶格有什麼索引? – Barmar 2014-10-30 10:04:29

+0

我沒有索引...只有主鍵 – user3878395 2014-10-30 10:05:23

+0

所以你希望人們分析你的查詢來得到你想要做的?請描述您的目標,並添加示例數據和預期輸出。你是creatint 2 subselects - 從來沒有好的表現。 – 2014-10-30 10:08:57

回答

0

嘗試創建你正在檢查的ID的索引。

在這種情況下,您可能需要創建一個索引:conv.user_id,datas.uid,m.message_id,messages.to_uid,messages.from_uid和datas.date也可能是一個好主意,因爲您對此重新排序。

0

from_uidto_uid上加上索引以加快SELECT MAX(message_id)子查詢。否則,它必須對錶格進行全面掃描。

0

我會嘗試和刪除子查詢(S)

您可以通過加入針對用戶兩次從TE獲得用戶的詳細信息時,清理了一下,到UID。這樣連接可以有效地使用索引。然後在SELECT中使用IF來決定要返回哪一個: -

SELECT IF (m.from_uid = 1, m.to_uid, m.from_uid) AS uid, 
     m.message, 
     m.sended AS `date`, 
     IF (m.from_uid = 1, CONCAT(to_conv.first_name, ' ', to_conv.last_name), CONCAT(from_conv.first_name, ' ', from_conv.last_name)) AS conversation_name 
FROM users u 
LEFT JOIN messages m 
ON m.from_uid = u.user_id 
LEFT JOIN users to_conv 
ON to_conv.user_id = m.to_uid 
LEFT JOIN users from_conv 
ON from_conv.user_id = m.from_uid 
WHERE m.message_id IN 
(
    SELECT MAX(message_id) 
    FROM messages 
    WHERE to_uid = 1 
    OR from_uid = 1 
    GROUP BY LEAST(from_uid, to_uid), 
    GREATEST(from_uid, to_uid) 
) 
ORDER BY date DESC 
LIMIT 5 

檢查消息ID的子查詢有點難以刪除。一般IN表現糟糕。可能值得改用它來使用EXISTS(儘管這將需要在HAVING子句中檢查可能不好)

SELECT IF (m.from_uid = 1, m.to_uid, m.from_uid) AS uid, 
     m.message, 
     m.sended AS `date`, 
     IF (m.from_uid = 1, CONCAT(to_conv.first_name, ' ', to_conv.last_name), CONCAT(from_conv.first_name, ' ', from_conv.last_name)) AS conversation_name 
FROM users u 
LEFT JOIN messages m 
ON m.from_uid = u.user_id 
LEFT JOIN users to_conv 
ON to_conv.user_id = m.to_uid 
LEFT JOIN users from_conv 
ON from_conv.user_id = m.from_uid 
WHERE EXISTS 
(
    SELECT MAX(message_id) AS max_message_id 
    FROM messages 
    WHERE to_uid = 1 
    OR from_uid = 1 
    GROUP BY LEAST(from_uid, to_uid), GREATEST(from_uid, to_uid) 
    HAVING m.message_id = max_message_id 
) 
ORDER BY date DESC 
LIMIT 5 
+0

你好,謝謝你的回覆...我試着這個查詢,沒有影響...我添加INDEXes到messages.from_uid和messages.to_uid與FOREIGN KEY到users.user_id並且也沒有效果:( – user3878395 2014-10-30 17:05:11

+0

請問您可以發佈實際的表聲明和一些測試數據嗎?然後我可以嘗試測試運行它(雖然明天我會得到一個機會現在) – Kickstart 2014-10-30 17:12:56