假设我们有一个受欢迎的网站.我们需要在用户之间实现类似邮件的消息传递.
典型的解决方案是使用2个表:
用户(user_id)
消息(message_id,sender_id(引用user_id),receiver_id(引用user_id),主题,正文).
该方法有2个显着的局限性
>所有用户的所有消息都存储在一个表中,导致其高负载并降低整体数据库性能.
>当有人需要同时向多个用户发送消息时,会复制该消息(recipients_count)次.
另一个解决方案使用3个表:
用户(USER_ID)
Sent_messages(sent_id,正文)
Received_messages(sent_id,正文)
received_messages的主题和正文从sent_messages的相应字段中复制.
这种方法导致
>通过将信息从一个表复制到另一个表来对数据库进行非规范化
>用户实际上可以删除发送/接收的消息,而无需从接收器/发送器中删除它们.
>消息占用的空间大约是2倍
>每张表的装载量减少约2倍.
所以这里提出问题:
>考虑到哪种设计更适合高负载和可扩展性? (我认为这是第二个)
>是否有其他数据库设计可以处理高负载?它是什么?有什么限制?
谢谢!
附:我知道在解决这些可扩展性问题之前,网站必须非常成功,但我想知道如果需要该怎么做.
UPDATE
目前,对于第一个版本,我将使用Daniel Vassallo提出的设计.但如果将来一切正常,设计将改为第二个.感谢Evert减轻了我的担忧.
users (user_id)
messages (message_id,sender_id,subject,
body)received_messages (message_id,user_id,address_mode,deleted)
这种模式可能比电子邮件更像推特,但它可能带来一些优势.
规则是:
>消息只能由一个用户发送,在每条消息的sender_id中引用.
>每个收件人都将在received_messages表中定义. address_mode字段可以定义消息是直接发送给收件人,还是作为CC发送,还是作为BCC发送.该字段显然是可选的.
>收件人删除的邮件将在received_messages表中标记已删除的标志.
>转发和回复的邮件需要使用新的sender_id重新创建.然后可以修改消息正文.
这些是一些优点:
>这比原始问题中提到的两个选项占用的空间更少,特别是如果用户通常会向多个收件人发送邮件.
>更容易缓存消息表,因为消息永远不会重复.
>删除邮件的收件人不会删除邮件发送给该用户的信息.它只会在received_messages表中标记为“已删除”.
>你还得到一个标准化的模型.
对于大多数应用程序,如果对上述模型使用乐观隔离级别,即使您希望以每秒几个的速率交换消息,也不应该存在性能问题.另一方面,如果您期望每秒有数百或数千条消息,那么考虑其他选项可能就是这种情况.