如何优化聊天室查询?

时间:2016-09-26 15:13:13

标签: sql sql-server database-design

背景

我正在为自定义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在下次运行查询时会在他的计费部门中出现意外。

1 个答案:

答案 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);

您当前的查询主要有两个问题:

  1. 左加入也会带来空白记录。此外,您将使用distinct处理的组中有多个记录。
  2. 记录列表再次加入所有消息表数据,因此如果消息表将包含更多数据,那么您的查询注定会变慢。
  3. 这与我们在https://www.applozic.com解决的问题类似。

    免责声明:我在Applozic工作。