big*_*801 31 php sql messaging database-design design-patterns
我正在创建一个类似于gmail和facebook的线程消息系统,其中收件箱列出显示主题的最新线程,发件人的姓名和最新消息的时间戳.
这是我的表格如何设置:
users:
    user_id
    user_name
thread:
    thread_id
    title
    to_id
    to_keep
    to_read
    from_id
    from_keep
    date
message:
    message_id
    thread_id
    to_id
    from_id
    message_text
    date
我现在正在做的是当用户创建新消息时,它在线程表中创建一个新线程,然后在消息表中创建一个新消息,如果用户响应一个线程,它会复制当前线程.线程表,除了它的交换to_id和from_id,然后创建基于一个新的消息.
此外,对于收件箱视图,我只能基于a查询所有线程user_id.所以,SELECT * FROM thread WHERE to_id = 2 and to_keep = TRUE ORDER BY date DESC或者如果我想在发件箱中查看消息,那就像是SELECT * FROM thread WHERE from_id = 2 and from_keep = TRUE ORDER BY date DESC.
如果用户在有新消息时打开一个线程,则to_read会更新为true UPDATE thread SET to_read = TRUE WHERE thread_id = 4.
我觉得我过度复杂化这个过程,应该有更好的方法来做到这一点.
任何帮助或想法将不胜感激.
这样我就可以从线程表中选择所有内容,然后使用user表进行连接,以显示我需要的所有内容.但是我觉得应该有更好的方法来做到这一点.
Joe*_*own 46
为什么不从用户对每条消息的视图中分离出消息关系?
我会通过消息上的自引用关系来进行线程化.换句话说,该消息具有"respond_to_message_id"列.
我不确定我理解为什么你有"to_id".邮件是针对个人用户的吗?这似乎非常有限.我认为你要么没有收件人(即收件人是任何人都可以阅读的留言板),要么你可以指定多个收件人,就像电子邮件一样.也许您可以解释有关系统如何使用的更多信息.
假设(为简单起见)你要发布到一个板上,所以只有"from"很重要,那么你就有了你的消息表,具有线程的自引用关系,用户表,然后是用户和消息之间的交集表存储每个用户已读取的消息.
这样,如果您想知道用户是否已阅读消息,只需尝试在交集表中读取给定消息的用户ID.如果不存在,那么该用户将读取该消息.
请注意,如果您希望拥有此设计的单个收件人,并且您希望拥有多个收件人,则可以使用交叉表来保存每封邮件的收件人列表.如果您有一个收件人交叉表,它可以作为您的读状态表执行双重任务.
编辑:ERD草图:
这是我正在谈论的快速草图......

发件人是否已选择保留邮件在邮件本身上标记.如果消息是新线程的开始,则reply_to_message_id列为NULL,否则为父消息的message_id.可以有多个收件人,每个收件人都有自己保留邮件的能力,以及跟踪收件人阅读邮件的日期和时间的能力.
编辑2:替代ERD和查询最近的消息
@OP询问如何查询线程中的最新消息.答案取决于线程的形式.你可以有一个扁平线程,其中每条消息都到达线性消息流的末尾,或者你可以有一个树形线程,其中每条消息都有一个特定的父节点,除非它是线程的根.在上面的ERD中,可以以任一方式使用reply_to_message_id字段.如果线程是平的,则FK始终是根MESSAGE.如果线程是树形的,那么FK就是回复MESSAGE的直接父级.
如果要运行的典型查询是"线程中最新消息是什么?" 并且您的线程是平的,那么您可以像这样使用SQL:
select top 1
  M.message_id
, M.sent_datetime
, M.title
, M.message_text
, S.user_id
, S.user_name
-- and anything else you want...
from MESSAGE M inner join USER S
  on M.sender_user_id = U.user_id
where M.reply_to_message_id = @ThreadRootMessageID
order by
  M.sent_datetime desc
另一方面,如果您的线程是树形的,并且这是一个您希望能够快速轻松地运行的查询,那么上面的ERD中的模式不是很容易使用.SQL不擅长树木.您可以通过一点非规范化来解决问题.请参阅下面的ERD:

请注意,现在有一个FK显示直接父级,一个FK显示根.由于线程不受编辑 - 至少在编辑消息根被指向不同线程的情况下,这需要的非规范化并不意味着更新异常的风险,因此冗余不会太成问题.
如果您使用此ERD,则查询"线程X中的最新消息"与上面相同,但在where子句中使用M.thread_root_message_id而不是M.reply_to_message_id.
| 归档时间: | 
 | 
| 查看次数: | 18861 次 | 
| 最近记录: |