评论系统设计实践

大前提: 我把评论和回复看作是不一样的两种内容,分别对待,如无特别说明,评论就是指直接针对主题的,回复是针对评论的

需要解决的问题: 1.每次拉列表都要去查评论(包含评论和回复)总数和每条评论下的总回复数
不同的设计方案
1.将评论表和回复表分开设计
评论表:CREATE TABLE `mt_comments` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '评论唯一ID', `topic_id` bigint(20) NOT NULL COMMENT '被评论的主题的唯一ID', `topic_type` int(4) NOT NULL COMMENT '被评论的主题的类型ID', `content` text NOT NULL COMMENT '评论的内容', `from_uid` bigint(20) NOT NULL COMMENT '评论者UID', `gmt_created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '评论创建时间', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8

是针对主题的评论,所以不需要存储to_uid字段
回复表:CREATE TABLE `mt_comment_replies` ( `id` int(11) NOT NULL COMMENT '回复唯一ID', `topic_id` bigint(20) NOT NULL, `topic_type` int(4) NOT NULL, `comment_id` bigint(20) NOT NULL COMMENT '被回复的评论的唯一ID', `content` text NOT NULL COMMENT '回复的内容', `from_uid` bigint(20) NOT NULL COMMENT '进行回复动作的用户的UID', `to_uid` bigint(20) NOT NULL COMMENT '被回复的用户UID', `reply_id` bigint(20) NOT NULL COMMENT '如果reply_type是评论类型,就是comment_id; 如果reply_type是回复类型,就是被回复的回复的唯一ID', `reply_type` tinyint(4) NOT NULL COMMENT '回复的类型有两种,一种是对评论的回复,另一种是对回复的回复', `gmt_created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '回复创建时间', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8

1.回复表我添加了一个comment_id字段来表示该回复挂在的根评论id,这样设计也是出于性能方面的考虑,我们可以直接通过评论id一次性的捞出该评论下的所有回复,然后通过程序来编排回复的显示结构。通过适当的冗余来提高性能也是常用的优化手段之一
2.因为是将回复单独分了一张表,如果需要获取评论总数,需要将评论表和回复表中对应一个topic的数量加在一起才是总评论数,两张表都增加了topic_id和topic_type,这样查询一个topic的回复总数就不用拿到评论表的id再去查回复表的回复总数了
2.单表设计
前提: 除了评论,所有的回复都是第二级,不做叠楼的操作

CREATE TABLE `mt_comments_tmp` ( `id` binary(20) NOT NULL COMMENT '评论ID', `comment_id` bigint(20) NOT NULL COMMENT '一级评论ID,该ID只会是评论的ID,不是回复的ID', `reply_id` bigint(20) NOT NULL COMMENT '该条内容的父级内容的ID,内容可以是评论,也可以是回复,如果是评论该值是0,如果是回复,该值是本条内容的父级的评论或回复的ID', `topic_id` bigint(20) NOT NULL COMMENT '主题唯一ID', `topic_type` tinyint(4) NOT NULL COMMENT '主题类型ID', `content` text NOT NULL COMMENT '评论或者回复的内容', `from_uid` bigint(20) NOT NULL COMMENT '发送内容的用户UID', `to_uid` bigint(20) NOT NULL COMMENT '被回复的用户的UID', `gmt_created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8

【评论系统设计实践】特别字段说明:
1.id,一条记录就是一条发表的内容,可做hash
2.comment_id,一级评论ID,该ID只会是评论的ID,不是回复的ID,方便拉取某一条评论下面的所有回复
3.reply_id,该条内容的父级内容的ID,内容可以是评论,也可以是回复,如果是评论该值是0,如果是回复,该值是本条内容的父级的评论或回复的ID,方便查询针对某一个回复下的所有回复
如果是叠楼的方式,如何实现 待完善。。。
使用mysql的注意小事项: mysql的字段unsigned属性不方便移植,所以我不使用
utf8mb4不只兼容utf8,还能比utf8能展示更新的字符,将编码改为utf8mb4外不需要做其他转换。评论内容字段使用utf8mb4 charset。表被设置之后,表中的字段会默认沿用表的字符集

    推荐阅读