【问题标题】:Should I denormalize in this situation?在这种情况下我应该非规范化吗?
【发布时间】:2016-05-13 08:47:19
【问题描述】:

我有两个表:conversationsmessages,每个对话都有很多消息

Message: (id, conversation_id, text, inserted_at, ...)
Conversation: (id, user_id ...)

我想显示一个对话列表,并为每个对话显示最近添加的消息的文本和时间戳。我还想根据最近添加的消息(最新消息在顶部)的时间戳对这些对话进行降序排序

目前,我使用 MAX 函数计算这些(以下是我的 ORM 生成的查询)

SELECT c0."id", MAX(m5."inserted_at"), 
        (SELECT data->>'text' FROM messages
        WHERE conversation_id = c0."id" AND type = 'message'
        ORDER BY inserted_at DESC
        LIMIT 1)
      , c4."unread_count", v6."name", v6."id", (SELECT array(
        SELECT type FROM tags
        WHERE conversation_id = c0."id")) FROM "conversations" AS c0 INNER JOIN "tags" AS t1 ON t1."conversation_id" = c0."id" LEFT OUTER JOIN "messages" AS m2 ON m2."conversation_id" = c0."id" INNER JOIN "conversation_users" AS c7 ON c7."conversation_id" = c0."id" INNER JOIN "users" AS u3 ON c7."user_id" = u3."id" INNER JOIN "conversation_users" AS c4 ON c4."conversation_id" = c0."id" INNER JOIN "messages" AS m5 ON m5."conversation_id" = c0."id" INNER JOIN "visitors" AS v6 ON v6."id" = c0."visitor_id" WHERE (t1."type" = $1) AND (NOT (m2."visitor_id" IS NULL)) AND (u3."id" = $2) AND (c4."user_id" = $3) GROUP BY c0."id", c4."unread_count", v6."id", v6."name" ORDER BY MAX(m5."inserted_at") DESC LIMIT 10

我的问题是,每次添加新消息时,将这些值非规范化并将它们直接保存在对话记录中是否更有意义?

在 has_many 关联上执行 3 MAX 似乎非常昂贵(仅 3000 条消息需要 600 毫秒)

【问题讨论】:

  • 你有合适的索引吗?旁注:NOSQL 数据库可能更适合这种用例。
  • 我对所有外键都有标准索引,并且我还在messages 表上索引了inserted_at 字段。
  • 我希望messagesinserted_at 上的索引在索引中具有对话ID。
  • 是的,我在两者上都有一个复合索引
  • 你能发布解释/执行计划吗?

标签: sql relational-database database-optimization


【解决方案1】:

当然,是的,你必须这样做! 在对话表中添加一个新字段。你去规范化了,但性能提升值得。

另一个选项,我不知道它是否符合您的要求,是将您的消息存储在对话表中的 xml 或 json 字段中。当然,我假设您除了从对话中选择消息之外什么都不做

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-04-08
    • 2012-06-02
    • 2018-05-30
    • 2011-01-17
    • 2022-07-22
    • 2013-05-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多