本文将从实际业务场景出发,拆解文章、点赞、收藏、评论等核心功能的数据库设计思路,并结合索引优化与Nginx+CDN部署架构,带你梳理一套高可用后端方案的落地实践。
1. 业务需求分析与表结构设计
后端业务通常涉及用户、文章、点赞、收藏、评论、标签、文件等核心实体。下面是我们梳理出的核心表及其设计要点。
用户表 (user)
用户表是系统的基础,为提升查询性能与扩展性,宜将其拆分为核心表与扩展信息表(如头像、个性签名)。id 作为主键自增,name 字段添加唯一索引以保证用户名不重复。
sql
sql
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
`password` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, -- 实际应存储加密后的密文
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`) -- 高频查询场景,覆盖按用户名搜索
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4_unicode_ci;
头像表 (avatar)
头像等静态资源建议存放到 OSS 或 CDN 服务上,数据库中仅存储元数据(如文件名、大小、关联用户ID),减轻应用服务器压力。
sql
sql
CREATE TABLE `avatar` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`mimetype` varchar(255) NOT NULL,
`filename` varchar(255) NOT NULL,
`size` int(11) NOT NULL,
`userid` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `userid` (`userid`) -- 加速根据用户ID查询头像的请求
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4_unicode_ci;
文章表 (post)
文章内容可能较大,使用 LONGTEXT 类型存储。userId 作为外键关联用户表,并建立索引以加速"查询某用户的所有文章"这一高频操作。
sql
less
CREATE TABLE `post` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(255) NOT NULL,
`content` longtext,
`userId` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `userid` (`userid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4_unicode_ci;
点赞表 (user_like_post)
点赞关系表使用联合主键 (userid, postid) 确保同一用户对同一篇文章只能点赞一次,同时建立 postid 索引用于统计文章获赞数。这里无需单独为 userid 建普通索引,因为联合主键的左前缀已能覆盖相关查询,避免空间浪费。
sql
go
CREATE TABLE `user_like_post` (
`userid` int(11) NOT NULL,
`postid` int(11) NOT NULL,
PRIMARY KEY (`userid`, `postid`),
KEY `postid` (`postid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4_unicode_ci;
评论表 (comment)
支持嵌套评论(楼中楼),通过 parentId 字段实现自关联。为便于查询,分别为 postId、userId 和 parentId 建立索引。外键约束采用 ON DELETE SET NULL 防止级联删除过多数据,保证数据一致性。
sql
r
CREATE TABLE `comment` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`content` longtext,
`postId` int(11) NOT NULL,
`userid` int(11) NOT NULL,
`parentId` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `postId` (`postId`),
KEY `userid` (`userid`),
KEY `parentId` (`parentId`),
CONSTRAINT `comment_ibfk_2` FOREIGN KEY (`parentId`) REFERENCES `comment`(`id`) ON DELETE SET NULL ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4_unicode_ci;
标签表 (tag) 与文章-标签关联表 (post_tag)
标签名采用唯一约束。关联表使用联合主键 (postId, tagId) 提高查询效率,并为 tagId 建索引以便查找使用了某标签的所有文章。
sql
less
CREATE TABLE `tag` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`)
);
CREATE TABLE `post_tag` (
`postId` int(11) NOT NULL,
`tagId` int(11) NOT NULL,
PRIMARY KEY (`postId`, `tagId`),
KEY `tagId` (`tagId`),
CONSTRAINT `post_tag_ibfk_1` FOREIGN KEY (`postId`) REFERENCES `post`(`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `post_tag_ibfk_2` FOREIGN KEY (`tagId`) REFERENCES `tag`(`id`) ON DELETE CASCADE ON UPDATE CASCADE
);
2. 索引优化策略思考
- 主键索引 :默认基于
id,用于快速定位单条记录。 - 唯一索引:保证业务字段唯一性,如用户名、标签名。
- 普通索引 :针对高频查询字段,如
userId、postId,显著提升查询效率。 - 联合索引 :如点赞表中的
(userid, postid),既满足唯一性约束,又能加速多条件查询。 - 外键索引:虽带来一定的插入性能损耗,但对保证数据完整性和关联查询优化仍有帮助。
3. 部署架构与静态资源加速
实际生产环境中,应用服务器通常部署在中央机房,并通过 Nginx 反向代理进行负载均衡。静态资源(图片、CSS、JS)则由 CDN 服务器就近提供服务。
- DNS 解析与负载均衡 :用户请求
juejin.cn域名后,经 DNS 解析返回最近的 Nginx 服务器 IP。Nginx 作为反向代理,将请求分发至后端集群中健康的服务实例。 - CDN 静态资源分离:头像、文件等资源上传至 OSS,并绑定 CDN 加速域名。数据库仅存储文件路径或元数据,前端直接拼接 CDN 地址访问,极大减轻源站带宽压力。
sql
less
-- 文件表示例,记录文件元信息并关联业务实体
CREATE TABLE `file` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`originalName` varchar(255) NOT NULL,
`mimetype` varchar(255) NOT NULL,
`filename` varchar(255) NOT NULL,
`size` int(11) NOT NULL,
`postId` int(11) DEFAULT NULL,
`userid` int(11) NOT NULL,
`width` smallint(6) NOT NULL,
`height` smallint(6) NOT NULL,
`metadata` json DEFAULT NULL,
KEY `postId` (`postId`),
KEY `userid` (`userid`)
);
通过合理的表设计、索引优化及动静分离部署,后端系统能在高并发场景下保持良好的性能与可扩展性。