MySQL 本身不提供“文章发布与管理”功能,它只是存储数据的工具;真正实现发布、编辑、分类、状态控制等逻辑,靠的是应用层(比如 PHP/Python/Node.js)对
INSERT、
UPDATE、
SELECT等操作的组织和权限控制。设计的关键在于表结构是否支撑业务动作,而不是“用 MySQL 做 CMS”。
文章主表必须包含哪些字段
一个可扩展的文章表不能只存标题和内容。核心字段要覆盖状态控制、时间线、作者归属和 SEO 基础:
id:主键,建议
BIGINT UNSIGNED AUTO_INCREMENT,避免后期 ID 溢出
title:
VARCHAR(200)足够,过长影响索引效率
slug:用于 URL 友好路径(如
/post/how-to-mysql-cms),需加
UNIQUE约束,且应用层保证生成逻辑唯一
content:用
LONGTEXT,别用
TEXT——后者最大仅 64KB,富文本或带代码块容易超限
status:
TINYINT或
ENUM('draft','published','archived'),比字符串查询快,也避免拼写错误
published_at:
DATETIME,显式记录发布时间,不要依赖
created_at——草稿可能创建多日才发布
author_id:外键指向用户表,别直接存用户名(违反范式,改名时难同步)
分类与标签要用独立关联表,别用逗号分隔
把分类写成
category VARCHAR(100)或用逗号存多个标签(如
'mysql,backend,optimization'),短期内省事,但后续查“所有 mysql 标签的文章”就得用
LIKE '%mysql%',无法走索引,数据一过万就卡。
正确做法是三张表:
categories:存分类名、
slug、
parent_id(支持多级)
tags:纯标签名,无层级
article_categories和
article_tags:都是双字段关联表(
article_id,
category_id),加联合索引
查某分类下全部文章,就走
JOIN article_categories ON ... WHERE category_id = ?,毫秒级响应。
预发布、定时发布靠 status + published_at 组合判断
很多 CMS 把“定时发布”做成后台轮询任务,其实 MySQL 层就能筛出待发布的文章:
SELECT * FROM articles WHERE status = 'draft' AND published_at <= NOW();
应用层每分钟执行一次这个查询,批量更新
status = 'published'即可。注意两点: 务必在
(status, published_at)上建复合索引,否则全表扫描 更新语句要加
LIMIT 100,防止单次处理太多锁表 别用
UPDATE ... SET status='published' WHERE published_at —— 这会把已发布的旧文章反复更新
搜索慢?先别急着上 Elasticsearch
小到中型站点(文章数
引擎用InnoDB(MyISAM 的全文索引不支持事务,且已废弃) 字段类型为
TEXT或
VARCHAR,且长度 ≥ 3 字符(
ft_min_word_len默认值) 建索引:
ALTER TABLE articles ADD FULLTEXT(title, content);查询用:
SELECT * FROM articles WHERE MATCH(title, content) AGAINST('mysql 性能优化' IN NATURAL LANGUAGE MODE);
如果搜索结果相关性差,优先调
IN BOOLEAN MODE或拆词优化,而不是立刻引入外部服务——运维复杂度和延迟成本往往被低估。
最常被跳过的其实是字符集和排序规则:
utf8mb4_unicode_ci是底线,否则 emoji、生僻字、某些语言的重音符号都会乱码或丢失。建库建表时漏掉这一句,后期迁移成本远高于初期多打几个字。
