我的博客的评论功能的实现,在之前的几篇文章中也有总结:
我在设计数据表时,是把所有的评论和回复都放在了同一张表中,之所以这么设计,主要是考虑到:
- 博客的数据量比较小,一张表就够了;
- 查询某文章下的评论时,查一次,就可以把所有评论和回复都查出来;
sql 语句:
SELECT c1.*, c2.nick as reply_nick, c2.face as reply_face
FROM comments c1
LEFT JOIN comments c2 ON c1.replyid = c2.id
WHERE c1.aid=?
查询出文章 id 下的所有评论,并且把回复的评论也查出来。若该评论的回复 id replyid
正好是某评论的 id,说明该评论是回复的某条评论,则把回复的评论的昵称、头像等数据也查出来。
但这种 SQL 语句的存在一个严重的问题:无法分页
。
假设每页的数据是 20 条,若我设置的 limit 为 20,其实查出来的是「评论+回复」一共 20 条,然后再形成楼中楼的结构后,当前页就不足 20 条数据了;而且还可能存在某条评论中的回复数据不全的问题。
那么该如何解决呢?
1. 查询出所有数据 #
就像上面的 sql 语句,把某文章里的所有评论数据都查出来,拼装成楼中楼的结构。要么后端根据页码分页后返回给前端;要么把所有数据返回给前端,前端自己进行分页。
其实在数据量不大的时候,这种做法没有问题,但是当数据量比较大的时候,每次都查询所有数据,然后再组装所有数据。速度肯定会逐渐慢下来。
2. 两次查询 #
既然「评论+回复」无法准确分页,那我们可以分成两次查询:
- 按照分页条数,查询出评论数据;
- 查询这些评论的所有回复的数据,这里不再分页;
大概的 SQL 语句如下:
# 查询评论数据,即replyid为null的数据
SELECT * FROM comments WHERE aid=? AND replyid IS NULL LIMIT ?, ?
再查询所有的回复数据:
# 将上面查到的所有评论的id给到当前语句
SELECT * FROM comments WHERE aid=? AND replyid IN (1,2,3)
然后将评论和回复的数据进行拼装。
3. 分成两张表 #
我们之前是把评论和回复放在一张表中。这里我们可以把评论数据和回复数据分别放到两张表里。类似于第 2 节中的两次查询,只不过这里查询的不同的数据表而已。