以下哪种数据库设计更适合内部邮件系统。
三张桌子:
MessageThread(models.Model):
- subject
- timestamp
- creator
Message(models.Model):
- thread (pk)
- content
- timestamp
- sender
MessageRecipient
- message_id (pk)
- recipient (pk)
- status (read, unread, deleted)
两张桌子:
Message
- thread_id
- subject
- content
- timestamp
- sender (fk)
MessageRecipient
- message_id (fk)
- recipient (fk)
- status (read, unread, deleted)
一个人优于另一个人的优势是什么?谢谢。
答案 0 :(得分:4)
第一个模式遵循更好的规范化规则,因此在大多数情况下可能更好。
拥有thread_id
,这基本上是一个自然键,不是另一个表的FK可能会遇到麻烦。当你想要它时,它是非常难以强制执行它是独一无二的,并且当你想要它时它是相同的。出于这个原因,我鼓励第一个建议的架构。
您的第二个架构允许为线程中的每条消息更改主题。如果这是您想要的功能,则不能使用第一个选项,因为您已经编写了它(但请参见下文)。
Message
- id
- parent (fk to Message.id)
- subject
- content
- timestamp
- sender (fk)
MessageRecipient
- message_id (fk)
- recipient (fk)
- status (read, unread, deleted)
您可以使用thread_id
概念,而不是parent
概念。然后每个回复都会指向原始邮件的记录。这允许线程,没有'线程'表。另一个可能的优点是,它也允许线程树。简而言之,您可以通过这种方式表示消息和回复之间更复杂的关系。如果您不关心这一点,那么这对您的申请来说不是奖励。
如果您不关心我刚刚提到的线程优势,我可能会建议您使用两种模式的混合:
MessageThread(models.Model):
- id
Message(models.Model):
- thread (pk)
- subject
- content
- timestamp
- sender
MessageRecipient
- message_id (pk)
- recipient (pk)
- status (read, unread, deleted)
这与第一个架构类似,不同之处在于我将“主题”列从MessageThread
移动到Message
表,以允许主题随着线程的进展而改变...我简单地使用MessageThread表作为Message中使用的线程ID的约束(克服了我在回答开头提到的限制)。您可能还希望在MessageThread表中包含其他元数据,但我会将其留给您和您的应用程序。
答案 1 :(得分:0)
如果稍后要添加一些额外的线程属性,例如“已锁定”,“粘性”或“重要”,则可以使用单独的MesageThread
表。选择一个更复杂的模型只是为了将来可能添加其他功能通常不是一个好主意。
第一个模型(带有MessageThread表的模型)保证线程中的所有消息都具有相同的主题,在第二个模型中,线程中的每个消息都可以具有不同的主题。这可能是好事还是坏事,具体取决于您希望消息传递如何工作。
第一个模型可以将message.thread_id
列声明为外键,因此您无法在没有有效线程引用的情况下插入消息。对于第二种模式,您没有这种保证。这可能会在以后引起一些错误。
我认为真正需要第一个模型中的MessageThread.timestamp
和MessageThread.creator
列;是不是与线程中第一条消息的时间戳和创建者相同?这种冗余可能会产生负面影响。
我会使用第一个模型,但我会删除MessageThread
中的创建者和时间戳字段。