繁体   English   中英

评论系统的 MYSQL 架构

[英]MYSQL schema for comment system

我正在使用下表设置创建的应用程序有一个基本的评论系统:

CREATE TABLE `meet_comment` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `meet_id` int(11) NOT NULL,
 `user_id` int(11) NOT NULL,
 `date_created` datetime NOT NULL,
 `comment` mediumtext NOT NULL,
 PRIMARY KEY (`id`),
 KEY `meet_id` (`meet_id`),
 KEY `user_id` (`user_id`),
 CONSTRAINT `meet_comment_ibfk_1` FOREIGN KEY (`meet_id`) REFERENCES `meet` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
 CONSTRAINT `meet_comment_ibfk_2` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci

meet_id是对用户评论的 object 的引用。 这很好用,尽管目前如果用户编辑评论,我只是在更新comment字段。

如果评论被编辑,我希望能够查看评论历史记录,go 对此的最佳方法是什么? 我猜我需要另一个包含评论和引用的表meet_comment.id 也许像:

CREATE TABLE `meet_comment` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `meet_id` int(11) NOT NULL,
 `user_id` int(11) NOT NULL,
 PRIMARY KEY (`id`),
 KEY `meet_id` (`meet_id`),
 KEY `user_id` (`user_id`),
 CONSTRAINT `meet_comment_ibfk_1` FOREIGN KEY (`meet_id`) REFERENCES `meet` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
 CONSTRAINT `meet_comment_ibfk_2` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci

CREATE TABLE `meet_comment_content` (
 `revision` int(3) NOT NULL,
 `meet_comment_id` int(11) NOT NULL,
 `date_created` datetime NOT NULL,
 `comment` mediumtext NOT NULL,
  UNIQUE KEY `revision_2` (`revision`,`meet_comment_id`),
 KEY `revision` (`revision`),
 KEY `meet_comment_id` (`meet_comment_id`),
 CONSTRAINT `meet_comment_content` FOREIGN KEY (`meet_comment_id`) REFERENCES `meet_comment` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci

如果是这样,查询表的最佳方法是什么,我猜我可以进行连接以获取所需的数据?

修改历史导致拉锯战——

  • 简单与否
  • 规模效率,或没有
  • 查询的复杂性,或不
  • 磁盘空间或膨胀

考虑以下“一般”原则:

有两张桌子:

  • Current -- 评论的当前版本
  • History ——评论的所有版本

Current使主要查询更简单、更高效。

创建或编辑评论意味着在Current中的INSERTUPDATE ,加上(总是)在History中的INSERT

HistoryCurrent的架构略有不同,因为需要有一个修订号,可能还有其他日期/标志/等。

这不解决磁盘空间问题; 我怀疑你可以持续一段时间才需要担心这些。 一种技术是“压缩”主TEXT列并将其放入BLOB中。 (注意:另一个架构差异。并增加了代码的复杂性。)典型的文本缩小了 3:1。

旁注: int(3) - (3)什么也没说。 一个INT总是 4 个字节。 建议使用SMALLINT UNSIGNED ,它占用 2 个字节,范围为 0..64K。

我会放弃FOREIGN KEYs ,尤其是CASCADE 这两个表中可能有一些参考资料会纠缠在一起。 无论如何,您需要仔细编写代码来处理各种任务,从而避免对 FK 的需求。

每个表都应该有一个PRIMARY KEY 对于数据的“聚类”,我推荐(comment_id, revision) ,而不是相反。

并且,考虑meet_id是否是 PK 的一部分。

-- User USR exists.
--
user {USR}
  PK {USR}
-- Meet MET exists.
--
meet {MET}
  PK {MET}
-- User USR attended meet MET.
--
user_meet {USR, MET}
       PK {USR, MET}

FK1 {USR} REFERENCES user {USR}
FK2 {MET} REFERENCES meet {MET}

如果用户对会议发表评论,则该用户参加了该会议。

-- User USR commented CMT_TXT on meet MET,
-- as comment number CMT_NO from that user on that meet.
--
comment {USR, MET, CMT_NO, CMT_TXT}
     PK {USR, MET, CMT_NO}

FK {USR, MET} REFERENCES user_meet {USR, MET}

-- For any given (USR, MET), CMT_NO is in {1,2,3 ...}.
-- User USR commented CMT_TXT on meet MET,
-- in version number VER_NO of comment number CMT_NO
-- from that user on that meet.
--
comment_history {USR, MET, CMT_NO, VER_NO, CMT_TXT}
             PK {USR, MET, CMT_NO, VER_NO}

     FK {USR, MET, CMT_NO} REFERENCES
comment {USR, MET, CMT_NO}
     ON UPDATE CASCADE
     ON DELETE RESTRICT

-- For any given (USR, MET, CMT_NO), VER_NO is in {1,2,3 ...}.

我建议将删除评论视为新版本。 例如,您可以将comment.CMT_TXT设置为空字符串。 这样,历史记录和数据完整性都得以保留。

如果comment_history仅包含旧版本,并且当前在comment中,则使用视图:

CREATE VIEW v_comment
AS
SELECT USR
     , MET
     , CMT_NO
     , 'current' as VER
     , CMT_TXT
FROM comment
UNION
SELECT USR
     , MET
     , CMT_NO
     , concat('ver_', lpad(VER_NO,3,0)) as VER
     , CMT_TXT
FROM comment_history ;

查询特定用户的评论和历史记录并满足:

SELECT *
FROM v_comment
WHERE USR = specific_user
  AND MET = specific_meet
ORDER BY CMT_NO, VER

笔记:

All attributes (columns) NOT NULL

PK = Primary Key
FK = Foreign Key

如果你不想 go 有太多复杂的查询和实现,你可以用简单的实现 go。

喜欢 JOIN

SELECT
  mc.id,
  mc.meet_id as meet_id,
  mc.user_id as user_id,
  mcc.revision as revision,
  mcc.date_created as date_created,
  mcc.comment as comment
FROM
  meet_comment as mc
LEFT JOIN
  meet_comment_content as mcc
ON
  mc.meet_id = mcc.meet_id

此查询将为您提供整个评论历史记录。

如果您想要某个特定用户的评论,那么您必须将其添加到

WHERE
    mc.user_id = <User Id>

如果您只想要来自特定会议 ID 和用户的评论,您可以将其添加到WHERE子句中。

WHERE
    mc.meet_id = <Meet ID> AND
    mc.user_id = <User ID>

设计数据库时的一些指示 -

  1. 在设计数据库时,逻辑上隔离数据是最好的方法。 例如 - comment表应该只有评论,没有关于会面或用户的信息。
  2. 映射应该有单独的映射表。 这将为您提供所需的灵活性。 因此,如果将来,让我们想要添加评论功能(嵌套评论),如 Reddit,您可以通过在主comment表中引入额外的parent_comment_id列轻松地做到这一点。

IMO应该有以下表格-

  1. user - user_id和其他与用户相关的字段
  2. meet - meet_id和其他与会议相关的字段
  3. comment - comment_idrevision_id和其他与评论相关的字段,例如
  4. user_meet_mapping - user_idmeet_id等。
  5. meet_comment_mapping - meet_idcomment_id等。

此模式是可以实现的最佳规范化。 就您的查询而言,您可以通过各种分页连接查询来提取它们。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM