我有以下数据透视表chat_user
将用户对象连接到聊天对象。
行为是任何数量的聊天可能存在,有2个或更多参与者。我在这里说明了这个案例。我正在尝试制定一个有效的查询,它将输入user_id 16和user_id 29391,并且如果这样的chat_id存在于这两个user_ids正好参与的情况下(本例中为chat_id 1),则将其返回以进行进一步处理。它应该忽略其他用户也参与的匹配,例如chat_id 2。
由于系统的设计方式,此表可能达到N ^ 2,其中N是用户数,而不考虑组聊天。我需要一个能够在合理的同步响应时间内处理这些数字(可能是数百万行)的查询,正如我所说的那样,听起来越来越不可能。
所以我正在寻找一个MySQL向导来告诉我这是否合理甚至可能,或者我是否应该认真重新设计这种安排。我这样做是为了支持1to1聊天和群聊,同时保持完整的参照完整性。我也试图尽可能多地重用代码,因为这个聊天只是大型Web应用程序的一个小组件。我真的试图避免不得不做1to1和群聊作为具有单独存储和所有的不同模型,但如果这是疯了,那么我别无选择。我以前在sql魔法方面取得了很好的成绩,所以我保持乐观。
另外请至少考虑适度的细节,在SQL方面我是新手,所以我可能无法将基本指令拼凑在一起。
TL; DR :将两个user_id作为输入的查询,并返回一个chat_id当且仅当恰好2行与给定的user_ids匹配且共有一些chat_id时。对于一个可能是百万富翁的排桌来说这太难了吗?
编辑::这是我目前正在做的工作
SELECT u1.chat_id
FROM chat_user u1
INNER JOIN chat_user u2
ON u1.chat_id = u2.chat_id
WHERE (u1.user_id = ? AND u2.user_id = ? )
AND u1.chat_id IN (SELECT chat_id
FROM chat_user
GROUP BY chat_id
HAVING Count(chat_id) = 2)
Edit2 :: copy-paste表让任何有兴趣快速尝试的人
CREATE TABLE `chat_user` (
`chat_id` int(10) UNSIGNED NOT NULL,
`user_id` int(10) UNSIGNED NOT NULL,
`engaged` tinyint(1) NOT NULL DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
INSERT INTO `chat_user` (`chat_id`, `user_id`, `engaged`) VALUES
(1, 16, 1),
(1, 29391, 1),
(2, 16, 1),
(2, 555, 0),
(2, 29391, 1),
(3, 14, 0),
(3, 29391, 1);
ALTER TABLE `chat_user` ADD PRIMARY KEY (`chat_id`,`user_id`);
答案 0 :(得分:1)
以下是我如何处理它:
SELECT u1.chat_id
FROM chat_user AS u1
JOIN chat_user AS u2
ON u1.chat_id = u2.chat_id
LEFT JOIN chat_user AS u3
ON u3.chat_id = u1.chat_id AND u3.user_id NOT IN (u1.user_id, u2.user_id)
WHERE u1.user_id = ? AND u2.user_id = ?
AND u3.chat_id IS NULL;
您需要(user_id, chat_id)
和(chat_id, user_id)
上的索引。您定义的主键足以用于后一索引。