CakePHP HAVING SUM查询超级 - 哪里有改进的余地?

时间:2014-11-15 05:03:04

标签: mysql cakephp having cakephp-2.5

此查询会终止整个页面(请求时间的90%):

/**
 * 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对话中是否有两个或更多用户是其中的一部分(作为$ users传递)。 有什么方法可以加快速度吗?

会话1:N ConversationUser N:1用户

记录不是太多:70k会话,130k会话用户

这也使用UUI而不是普通的AIID整数这一事实可能会使情况变得更糟。 但它仍然不应该是5s。

1 个答案:

答案 0 :(得分: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);
}