评论表必须包含哪些核心字段
一个能跑起来的评论系统,
comments表至少得有
id、
post_id(关联文章)、
content(正文)、
created_at(时间)、
status(审核状态)这 5 个字段。缺
status容易被灌水;不加
post_id就没法知道评论属于哪篇文章;
created_at不设默认值
CURRENT_TIMESTAMP,后期查数据会很被动。
常见错误:把用户信息(如昵称、邮箱)直接存进
comments表。这样会导致修改用户资料时要批量更新评论表,也违背范式。正确做法是只存
user_id,再通过关联查用户表。
id类型用
BIGINT UNSIGNED AUTO_INCREMENT,避免将来评论量大时溢出
post_id和
user_id必须加索引,否则按文章查评论会变全表扫描
content推荐用
TEXT,别用
VARCHAR(1000)—— 用户真写长评时会被截断
如何支持二级回复(即“回复某条评论”)
靠一个
parent_id字段就能实现。它默认为
0或
NULL,表示一级评论;如果指向另一个
comments.id,就是二级回复。注意:这个字段必须允许为
NULL,且要加索引,否则查某条评论的所有子回复会极慢。
实际查询时,不能只靠一次
JOIN拿到完整树形结构——MySQL 原生不支持递归 CTE(8.0+ 虽支持,但深度有限且性能差)。生产环境更推荐“查两次”:第一次查一级评论,第二次用
WHERE parent_id IN (…)查所有子回复,应用层拼装。
CREATE TABLE comments ( id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, post_id BIGINT UNSIGNED NOT NULL, user_id INT UNSIGNED NOT NULL, parent_id BIGINT UNSIGNED NULL, content TEXT NOT NULL, status TINYINT NOT NULL DEFAULT 1 COMMENT '1=待审,2=通过,3=拒绝', created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, INDEX idx_post_id (post_id), INDEX idx_user_id (user_id), INDEX idx_parent_id (parent_id) );
防刷和基础审核怎么落地到建表和 SQL 层
数据库层面能做的有限,但几个关键约束能拦住明显异常:
对同一post_id+
user_id+
content组合加唯一索引,防止用户重复提交相同评论
status字段用
TINYINT而非
VARCHAR,减少存储和比对开销 加
updated_at字段并设触发器自动更新,方便后台识别“被编辑过”的评论
注意:不要在数据库里做 IP 记录或频率限制——这些该由应用层或 Nginx 处理。MySQL 的
INSERT ... ON DUPLICATE KEY UPDATE可用于幂等提交,但仅限简单场景;复杂逻辑(比如 5 分钟内只允许发 1 条)必须在代码里控制。
查询某篇文章的评论列表时最容易忽略的性能点
最常被忽视的是
ORDER BY created_at DESC LIMIT 20这类语句没走对索引。即使有
idx_post_id,MySQL 仍可能先过滤再排序,导致 Using filesort。
解决办法是建联合索引:
INDEX idx_post_status_time (post_id, status, created_at)。这样 WHERE post_id = ? AND status = 2 就能直接定位,再按
created_at倒序取前 20 条,全程走索引。
另外,如果评论数超过 10 万,
LIMIT 100000, 20会越来越慢。这时要么改用游标分页(用上一页最后一条的
created_at和
id作为下一页条件),要么加缓存层,别硬扛。
