下面是一个有效的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
答案 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