2014-11-15 59 views
0

該查詢殺死整個頁面(90%的請求時間):CakePHP HAVING SUM查詢superslow - 哪裏有改進的餘地?

/** 
* Checks if a conversation exists containing these users (at least two!) 
* //TODO: fixme! SUPER-SLOW! 5s on a 6s page load total 
* 
* @param array $users Users to check on 
* @param int $limit Limit - needs at least 2 users 
* @return array Results 
*/ 
public function partOfConversations($users, $limit = 5) { 
    $options = array(
     'conditions' => array('ConversationUser.status <' => ConversationUser::STATUS_REMOVED), 
     'group' => array('ConversationUser.conversation_id HAVING SUM(CASE WHEN ConversationUser.`user_id` in (\'' . implode('\', \'', $users) . '\') THEN 1 ELSE 0 END) = ' . count($users) . ''), 
     'contain' => array('Conversation' => array('LastMessage')), 
     'limit' => $limit, 
     'order' => array('Conversation.last_message_id' => 'DESC') 
    ); 
    return $this->ConversationUser->find('all', $options); 
} 

結果查詢是

SELECT `ConversationUser`.`id`, `ConversationUser`.`conversation_id`, 
    `ConversationUser`.`user_id`, `ConversationUser`.`status`, `ConversationUser`.`created`, 
    `Conversation`.`id`, `Conversation`.`user_id`, `Conversation`.`title`, 
    `Conversation`.`created`, `Conversation`.`last_message_id`, `Conversation`.`count` 
FROM `comm_conversation_users` AS `ConversationUser` 
LEFT JOIN `comm_conversations` AS `Conversation` 
    ON (`ConversationUser`.`conversation_id` = `Conversation`.`id`) 
WHERE `ConversationUser`.`status` < 7 GROUP BY `ConversationUser`.`conversation_id` 
HAVING SUM(CASE WHEN `ConversationUser`.`user_id` in 
    ('2ed23d7c-dcc8-4d3b-8e7b-0fe018b0f9bf', '297e0fcc-8880-4bc7-9b57-0ba418b0f9bf') 
    THEN 1 ELSE 0 END) = 2 
ORDER BY `Conversation`.`last_message_id` DESC 
LIMIT 5 

什麼它試圖做的是在1找出是否.. x對話中有兩個或更多用戶是其中的一部分(以$用戶身份傳遞)。 有什麼辦法可以加快速度嗎?

對話1:N ConversationUser N:1個用戶

記錄都沒有太多:70K對話,130K ConversationUser

,這也使用的UUID,而不是正常的AIID整數可能是使情況變得更糟的事實。 但它應該仍然不是5秒。

+0

可以提供有關數據庫表結構的詳細信息?比如你對這個查詢中使用的表有什麼索引? –

+0

添加到@gurel_kaynak請求時,應該通過另一個工具(例如,命令行)運行該查詢,前面加上術語'EXPLAIN'。這將顯示使用的索引。 IMO:你需要在comm_conversation_users.status上有一個索引。 – AgRizzo

+0

索引是對話:id(主要),user_id - ConversationUser:id(主要),user_id,conversation_id。爲狀態添加索引並沒有幫助。無論如何,這個領域已經很小(2)了。 – mark

回答

1

除了確保您的SQL表通過索引進行優化,我認爲你應該添加另一個條件 - 只有那些記錄與可接受的user_id的。

這裏是適當的WHERE子句

WHERE `ConversationUser`.`status` < 7 
    AND `ConversationUser`.`user_id` in 
    ('2ed23d7c-dcc8-4d3b-8e7b-0fe018b0f9bf', '297e0fcc-8880-4bc7-9b57-0ba418b0f9bf') 

PHP代碼更改爲:

public function partOfConversations($users, $limit = 5) { 
    $options = array(
     'conditions' => array('ConversationUser.status <' => ConversationUser::STATUS_REMOVED 
           ,'ConversationUser.user_id' => $users), 
     'group' => array('ConversationUser.conversation_id HAVING SUM(CASE WHEN ConversationUser.`user_id` in (\'' . implode('\', \'', $users) . '\') THEN 1 ELSE 0 END) = ' . count($users) . ''), 
     'contain' => array('Conversation' => array('LastMessage')), 
     'limit' => $limit, 
     'order' => array('Conversation.last_message_id' => 'DESC') 
    ); 
    return $this->ConversationUser->find('all', $options); 
} 
+0

太棒了!事情是,在另一個類似的查詢中,我似乎有附加條款。我不知道爲什麼我沒有這個了。但它現在運行速度非常快。非常感謝! – mark