2

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

我最初以为我什至可以将 COUNT 替换为 FIRST 以进行一些简单的优化,但不能使用 MySQL ......

(我看过这个问题,但是 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
4

3 回答 3

1

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

我不能保证这会让你的查询运行得更快,但我也不相信你有任何需要努力进行这种优化的问题(我认为“这种”是指“过早”)。

于 2012-08-10T16:34:29.940 回答
0

在 SQL Server 中,我会这样做:

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

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

于 2012-08-10T16:34:03.030 回答
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
于 2012-08-10T16:57:00.247 回答