我正在为自定义Web应用程序构建一个简单的聊天客户端。我需要存储所有聊天记录。用户还可以向个人或群组发送消息。认为谷歌聊天(我告诉我的客户使用,但他坚持自定义)。我的数据库结构如下:
表: ChatRoom
int主键 ChatRoomID
varchar(64)名称表 ChatMessage
int主键 ChatMessageID
int UserID
int ChatRoomID
varchar(2000)消息
datetime date表 ChatUser
int ChatRoomID
int UserID
int LastMessageID 主键(ChatRoomID,UserID)
我正在使用SQL Server,并将很快迁移到mysql,因此解决方案需要在两个平台上运行。
假设用户刚刚登录,我需要提取包含未完成消息的所有聊天室的列表。我当前的查询如下所示:
SELECT DISTINCT
cr.ChatRoomID AS id,
cu.LastMessageID AS label
FROM ChatRooms cr
LEFT JOIN ChatUsers cu ON cu.ChatRoomID = cr.ChatRoomID
LEFT JOIN ChatMessages cm ON cm.ChatRoomID = cr.ChatRoomID
WHERE cu.UserID = :user_id
AND cu.LastMessageID < cm.ChatMessageID
这似乎运作得相当好。但是我怀疑当他们有数十个用户,数千个房间和数百万条消息时,效率会降低。如何优化此查询(或数据库结构)以使此请求(具有针对给定用户的未完成消息的聊天室数量)成为可扩展性能的查询?
我主要担心的是我被迫为此查询使用“distinct”标志。因此,这可能是将数百万的临时表加入到过滤到2个数字之前。
用户
1 | A
博士 2 | B博士 3 |记者A
4 |记者B
5 |老板聊天室
1 |医生集团 2 |计费组ChatUser
房间|用户|消息
- | - | -------
1 | 1 | 0
1 | 2 | 2
1 | 5 | 2
2 | 3 | 6
2 | 4 | 0
2 | 5 | 5聊天留言
ID |房间|用户|消息
- | - | - | -------
1 | 1 | 5 | “今天大家怎么样?” 2 | 1 | 2 | “我很好。在5号房需要更多的乐队辅助工具。” 3 | 2 | 5 | “有人可以用Band Aids补充5号房间吗?” 4 | 2 | 3 | “那不是我的工作得到了一个傻瓜。” 5 | 2 | 5 | “不管怎么说还是你被解雇了。” 6 | 2 | 3 | “这不是你的,我退出了。”
在这种情况下,用户1和4的工作时间较晚,当他们登录时会弹出一条消息,用户5在下次运行查询时会在他的计费部门中出现意外。
答案 0 :(得分:4)
您可以像这样优化此查询:
select cr.ChatRoomID AS id,
cu.LastMessageID AS label
from ChatUsers cu inner join ChatRooms cr ON cu.ChatRoomID = cr.ChatRoomID
where cu.UserID = :user_id and
exists (select 1 from ChatMessages cm where cm.ChatRoomID = cr.ChatRoomID and cu.LastMessageID < cm.ChatMessageID);
您当前的查询主要有两个问题:
这与我们在https://www.applozic.com解决的问题类似。
免责声明:我在Applozic工作。