一、写在前面
最近在写博客的留言功能,由此引发的思考,留言一般分为简单留言和盖楼留言
简单留言:一问一答,对于没有大量用户评论或者评论不是核心功能的app来说就够用了。
盖楼留言:有着大量的用户评论,那么设计“盖楼”的效果还是可取的,这样能帮助用户找到该条评论或者回复的上下文情景。但是根据“盖楼”的显示效果不同,设计上也是有很大的差别的。
如何设计一个简洁优雅的盖楼留言呢?下面让我们带着这个问题进入今天的课题
二、盖楼设计
数据库结构模型如下:
create table ArticleComment(
@ID int, --标识列
@PID int, --回复ID
@ArticleID int, --文章ID
@Content ntext, --内容
@IP nvarchar(50), --IP
@AddDate DateTime --留言时间
)
方法一:
复制前面回复,附加上新的,一同放入 Content 中。Content 要足够大,足以放下所有的楼层。
这样做有两个缺点:
1. 占用空间大
2. 前面的回复后修改后,后面的不好更新
方法二:
递归,需要程序查询所需和前端做必要的处理合并就可以达到效果。这里又引出另外一个问题“当留言回复的层数过多的时候,比如1万条盖楼,会极大拖慢系统的加载时间。”
一种解决方案:
1.文章留言分页加载
2.每个父ID下面只能挂在留言级数需要控制,多余的下一页显示。页面由用户触发
三、盖楼总结
上面只是简单列举目前市面的上几种留言实现方式,如果你的系统每天都会有成千上万条评论,那么单表的设计肯定是不行,优化的方式也有很多。
- 分库分表。分库分表是最为常用也最有效的优化方式,建议按照主题来分库分表。这样同一个主题下面的评论就会落到同一张表里,避免了跨表查询。
- 适当的数据冗余。如果你需要显示评论人的相关信息,那么在插入评论时就把这些信息写入评论表中,避免多次查询。实际上,如果是纪录数据,都可以冗余对应的数据信息,因为它们的数据的实时行和一致性要求并不高,用户不会因为评论中的头像没更新而撕了你,哈哈。
- 如果pd要求你能给评论点赞,得注意点赞幂等性,同一个用户只能点一次赞或者取消自己的点赞。因为从幂等性的要求来说,每个赞都是一条记录。评论的赞数如果都从点赞表中统计得出,那么性能开销会十分巨大,而且点赞如此轻量级的一个操作一定会加剧点赞表的竞争操作。所以建议直接在评论表中添加一个
like_count
的计数器,维护该冗余该字段。减轻服务器聚合数据的压力,热门评论加缓存。类似于网易新闻的热门评论,读取频度非常高,可以专门开接口给客户端,同时该接口做缓存。