我有两张桌子:
user:id,name message:sender_id,receiver_id,message,read_at,created_at
我需要检索2个结果,并且我正在尝试找到最佳解决方案。我已经包含了我最后使用的查询。
我需要检索一个用户列表,并且每个用户都有可用的信息是否有来自每个用户的任何未读消息(他们作为发件人,我作为接收者)以及是否有任何读取消息在我们之间(他们发送我是接收者或我发送他们是接收者)
我需要与上面相同,但只包括我们之间有任何消息传递的成员,先按未读,然后按最后收到的消息排序。
在第一种情况下,我不需要计数,我只需要知道是否至少有一条未读消息。我正在发布代码和我当前的查询,请在有机会时查看:
顺便说一下,在拳头查询中,一切都是我想要的方式。我担心的是:在第二个查询中,我想通过messages.created_at订购,但我不认为我可以通过分组来做到这一点?而且我也不知道这种方法是否是最优化和最快速的。
CREATE TABLE `user` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
)
INSERT INTO `user` VALUES (1,'User 1'),(2,'User 2'),(3,'User 3'),(4,'User 4'),(5,'User 5');
CREATE TABLE `message` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`sender_id` bigint(20) DEFAULT NULL,
`receiver_id` bigint(20) DEFAULT NULL,
`message` text,
`read_at` datetime DEFAULT NULL,
`created_at` datetime NOT NULL,
PRIMARY KEY (`id`)
)
INSERT INTO `message` VALUES (1,3,1,'Messge',NULL,'2010-10-10 10:10:10'),(2,1,4,'Hey','2010-10-10 10:10:12','2010-10-10 10:10:11'),(3,4,1,'Hello','2010-10-10 10:10:19','2010-10-10 10:10:15'),(4,1,4,'Again','2010-10-10 10:10:25','2010-10-10 10:10:21'),(5,3,1,'Hiii',NULL,'2010-10-10 10:10:21');
SELECT u.*, m_new.id as have_new, m.id as have_any
FROM user u
LEFT JOIN message m_new ON (u.id = m_new.sender_id AND m_new.receiver_id = 1 AND m_new.read_at IS NULL)
LEFT JOIN message m ON ((u.id = m.sender_id AND m.receiver_id = 1) OR (u.id = m.receiver_id AND m.sender_id = 1))
GROUP BY u.id
SELECT u.*, m_new.id as have_new, m.id as have_any
FROM user u
LEFT JOIN message m_new ON (u.id = m_new.sender_id AND m_new.receiver_id = 1 AND m_new.read_at IS NULL)
LEFT JOIN message m ON ((u.id = m.sender_id AND m.receiver_id = 1) OR (u.id = m.receiver_id AND m.sender_id = 1))
where m.id IS NOT NULL
GROUP BY u.id
答案 0 :(得分:1)
第一个查询:
SELECT u.*,
EXISTS
(
SELECT NULL
FROM message
WHERE sender_id = u.id
AND receiver_id = 1
AND read_at IS NULL
) have_new,
EXISTS
(
SELECT NULL
FROM message
WHERE (
sender_id = u.id AND receiver_id = 1
OR sender_id = 1 AND receiver_id = u.id
)
AND read_at IS NOT NULL
) have_any
FROM user u
第二个问题:
SELECT u.*,
EXISTS
(
SELECT NULL
FROM message
WHERE sender_id = u.id
AND receiver_id = 1
AND read_at IS NULL
) have_new,
(
SELECT created_at
FROM message
WHERE (
sender_id = u.id AND receiver_id = 1
OR sender_id = 1 AND receiver_id = u.id
)
ORDER BY
created_at DESC
LIMIT 1
) last_message
FROM (
SELECT DISTINCT sender_id AS party
FROM message
WHERE receiver_id = 1
UNION
SELECT DISTINCT receiver_id
FROM message
WHERE sender_id = 1
) m
JOIN user u
ON u.id = m.party
ORDER BY
have_new DESC, last_message DESC
创建以下索引:
messages (sender_id, receiver_id, last_message)
messages (receiver_id, sender_id, last_message)
答案 1 :(得分:0)
我非常确定JOIN
的性能比子查询更高。我看到的一个问题是表创建脚本中没有任何日期或外键索引。你会想要那些。如果我正确理解你的问题,这就是我如何完成查询#2:
SELECT u.*,
m_new.id AS have_new,
MAX(m_new.created_at) AS new_created,
m.id AS have_any,
MAX(m.created_at) AS created
FROM USER u
LEFT JOIN message AS m_new
ON u.id = m_new.sender_id
AND m_new.receiver_id = 1
AND m_new.read_at IS NULL
LEFT JOIN message AS m
ON (u.id = m.sender_id AND m.receiver_id = 1)
OR (u.id = m.receiver_id AND m.sender_id = 1)
WHERE m.id IS NOT NULL
GROUP BY u.id
ORDER BY new_created DESC,
created DESC
;
以下是JOIN
s vs子查询中的SO中的几个好链接: