我应该在这种情况下反规范吗?

时间:2016-05-13 08:47:20

标签: sql relational-database database-optimization

我有两个表: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毫秒)

1 个答案:

答案 0 :(得分:0)

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

另一个选项,我不知道它是否符合您的要求,是将您的消息存储在对话表的xml或json字段中。当然,我认为除了从对话中选择消息之外你别做其他事情