优化GROUP_BY查询中的COUNT(*)

时间:2012-08-10 16:23:31

标签: mysql sql count sql-optimization

下面是一个有效的SQL查询,它返回按用户的多个帐户分组的未查看邮件计数列表。但是,我们实际上并不需要计数,只是表示存在未查看的消息。如果不拆分相当复杂的JOIN逻辑,你能看到一种通过用EXISTS / HAVING / DISCTINCT 1或其他技术替换COUNT来优化查询的方法吗?

我最初认为我甚至可以用FIRST替换COUNT以进行一些简单的优化,但是没有使用MySQL ......

(我看过this question,但GROUP BY让我很难应用我见过的任何替代方案。

SELECT messages_to_user.account_id, COUNT(*) FROM

(SELECT message.id as id, root_message.account_id as account_id
    FROM message
    JOIN message as root_message 
    on message.conversation_id = root_message.id
    AND (root_message.created_by = {user_id}
    OR root_message.to_user_id = {user_id}
    OR root_message.to_user_id IS NULL)
    AND message.created_by != {user_id}
) messages_to_user

LEFT JOIN

(SELECT 
    message_view.id as id, 
    message_view.message_id as message_id,
    message_view.user_id as user_id
    FROM message_view
    WHERE message_view.user_id = {user_id}) viewed_messages

ON messages_to_user.id = viewed_messages.message_id

WHERE viewed_messages.id IS NULL

GROUP BY messages_to_user.account_id

3 个答案:

答案 0 :(得分:1)

如果您不需要计数,只需从第一行的SELECT中省略COUNT(*)。

我不能保证这会让你的查询运行得更快,但我也不相信你有任何需要花费在这种优化上的问题(在这种情况下,我觉得我意思是“过早”)。

答案 1 :(得分:0)

在SQL Server中,我会这样做:

case when exists(select * from messages where IsUnread = 1) then 1 else 0 as HasUnreadMessage

这显然是伪代码。可能你可以让它适用于MySQL。存在检查应该便宜得多,因为它可以在找到一行时停止。

答案 2 :(得分:0)

如何减少要连接的子查询的大小:

SELECT DISTINCT messages_to_user.account_id FROM

(SELECT DISTINCT message.id as id, root_message.account_id as account_id
    FROM message
    JOIN message as root_message 
    on message.conversation_id = root_message.id
    AND (root_message.created_by = {user_id}
    OR root_message.to_user_id = {user_id}
    OR root_message.to_user_id IS NULL)
    AND message.created_by != {user_id}
) messages_to_user

LEFT JOIN

(SELECT DISTINCT message_id
    FROM message_view
    WHERE message_view.user_id = {user_id}) viewed_messages

ON messages_to_user.id = viewed_messages.message_id

WHERE viewed_messages.message_id IS NULL