公告表必须包含状态字段和发布时间精度控制
公告不是一发就完事,需要支持草稿、已发布、已过期、已撤回等生命周期管理。直接用
status TINYINT(0=草稿,1=发布,2=过期,3=撤回)比布尔值更可持续;发布时间必须用
publish_time DATETIME而非
created_at,因为创建时间和实际对外展示时间常不一致。 避免用
is_published BOOLEAN:后期加“定时发布”“撤回重发”时会卡死
publish_time建议设默认值
CURRENT_TIMESTAMP,但允许为空,方便存草稿时不填 如果需毫秒级定时(比如精确到秒内推送),用
publish_time DECIMAL(13,3)存 Unix 时间戳(PHP/Java 易处理),MySQL 8.0+ 也可用
TIMESTAMP(3)
分类与标签应分离,优先用多对多关联而非 JSON 字段
公告常需按“系统通知|活动公告|维护提醒”分类,还可能打“紧急|重要|普通”标签。别把分类 ID 和标签数组塞进一个
category_json TEXT字段——查起来慢,没法索引,改起来容易错。 建独立
notice_categories表,主键
id+
name+
code(如
'maintenance') 建关联表
notice_category_map:字段为
notice_id、
category_id、
is_primary TINYINT(标出主分类) 标签同理,用
notice_tags+
notice_tag_map;除非标签数固定且极少(≤3),否则别用逗号分隔字符串
内容存储要区分富文本与纯文本,且必须限制长度
前端编辑器输出的 HTML 内容动辄上万字符,但 MySQL 的
TEXT类型在排序、WHERE 查询时性能差;而纯文本摘要又不能丢——搜索、列表预览、微信服务号推送都靠它。 必存两个字段:
content_html MEDIUMTEXT(完整 HTML)、
content_plain VARCHAR(2000)(自动提取的纯文本摘要) 禁止用
LONGTEXT:除非你确定单条公告超 4GB,否则浪费空间且影响 InnoDB 缓冲池效率 插入前强制截断
content_plain到 2000 字符(用
SUBSTRING_INDEX(SUBSTRING(content_html, 1, 5000), '', 1)等逻辑预处理),防止超长报错
读多写少场景下,务必加覆盖索引避免回表
公告列表页查的是“状态=1 且 publish_time ≤ NOW()”,返回 id/title/publish_time/status —— 如果只在
status和
publish_time上分别建索引,MySQL 仍要回表取 title,QPS 高时 I/O 成瓶颈。 建联合索引:
INDEX idx_status_time (status, publish_time)再加覆盖索引:
INDEX idx_status_time_cover (status, publish_time, id, title),让查询完全走索引不回表 注意:
status必须放联合索引最左,因为 WHERE 中是等值过滤;
publish_time是范围查询,放其后 真实项目里最容易被跳过的,是草稿状态下的
publish_time允许为空 + 联合索引中
status的低基数导致优化器误选索引——上线前一定用
EXPLAIN验证公告列表 SQL 是否命中覆盖索引。
