【问题标题】:How can I optimize a chat room query?如何优化聊天室查询?
【发布时间】:2016-09-26 15:13:13
【问题描述】:

背景

我正在为自定义 Web 应用程序构建一个简单的聊天客户端。我需要存储所有聊天记录。用户还可以向个人或群组发送消息。想想谷歌聊天(我告诉我的客户改用它,但他坚持自定义)。我的数据库结构如下:

表格:聊天室
int 主键 ChatRoomID
varchar(64) 名称

表格ChatMessage
int 主键 ChatMessageID
int 用户 ID
int ChatRoomID
varchar(2000) 消息
日期时间 日期

表格 ChatUser
int ChatRoomID
int 用户 ID
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 |计费组

聊天用户
房间 |用户 |留言
- | - | --------
1 | 1 | 0
1 | 2 | 2
1 | 5 | 2
2 | 3 | 6
2 | 4 | 0
2 | 5 | 5

聊天消息
身份证 |房间 |用户 |留言
- | - | - | --------
1 | 1 | 5 | “今天大家好吗?”
2 | 1 | 2 | “我很好。5 号房间需要更多创可贴。”
3 | 2 | 5 | “有人可以用创可贴补给 5 号房间吗?”
4 | 2 | 3 | “找个走狗不是我的工作。”
5 | 2 | 5 | “无论如何都要这样做,否则你就被解雇了。”
6 | 2 | 3 | “这是你的不是你的,我退出了。”

在这种情况下,用户 1 和 4 上班迟到,当他们登录时会弹出一条消息,下次我运行查询时,用户 5 会在他的计费部门遇到惊喜。

【问题讨论】:

  • 您能否提供一些测试数据供我们测试和了解可扩展性方面
  • 还有实际的 ddl 包括索引。
  • 我不知道ddl是什么,索引应该很明显。我确实添加了一个示例场景。
  • ddl = 数据定义语言(创建表的脚本)。仅仅因为索引应该是显而易见的并不意味着您已经正确定义了它们。索引是优化中非常关键的部分。
  • 我不需要关于索引的帮助 我需要帮助编写一个好的查询假设索引与它们显示的完全一样(房间 == 房间、消息 == 消息等)。另一种表结构也是可以接受的。

标签: sql sql-server database-design


【解决方案1】:

你可以像这样优化这个查询:

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. 记录列表将再次连接所有消息表数据,因此如果消息表将包含更多数据,那么您的查询注定会变慢。

这与我们在https://www.applozic.com 解决的类似问题。

免责声明:我在 Applozic 工作。

【讨论】:

  • 这似乎消除了消息表的大量连接。但是不是为包装查询的每个结果都执行子查询吗?我觉得这可能会产生类似的问题。
  • 这样,每当获取第一条记录时,查询将停止并为另一条记录运行。另一种优化方法是在发布新消息时将消息时间戳保存在 ChatUser 表中,并根据保存的时间戳检查 LastMessageId 的时间戳。
猜你喜欢
  • 1970-01-01
  • 2014-06-17
  • 1970-01-01
  • 2014-09-22
  • 2021-12-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-02
相关资源
最近更新 更多