Typecho的数据库设计的学习
Typecho是一款仿Wordpress,但相对Wordpress要简单的多的开源博客程序。开发者大量的参考了WordPress的设计,去除了一些高级复杂的功能,实现了一个小而美的博客系统。它的优点:
轻量高效:仅仅 7 张数据表,加上不足 400KB 的代码,就实现了完整的插件与模板机制。超低的 CPU 和内存使用率,足以发挥主机的最高性能。
先进稳定:原生支持 Markdown 排版语法,易读更易写。支持 BAE/GAE/SAE 等各类云主机,即使面对突如其来的高访问量,也能轻松应对。
简洁友好:精心打磨过的操作界面,依然是你熟悉的面孔,更多了一份成熟与贴心。每一个像素的剪裁,都只为离完美更进一步。
一起来看下7张表的数据库的数据库设计,看从中能学到什么。
Typecho数据库设计
设计思路
Typecho的定位是单用户blog系统,当在设计一个单用户blog系统时要时刻把“单用户”这三个字放在心上。单用户意味着数据的查询是很集中的,当一个用户页面的访问量比较小时他几乎感觉不到多出的几次查询带来多少延迟。而当访问量比较大时他必然有实力去升级他的系统。由于单用户系统的查询比较集中,可以通过部署文件缓存或者内存对象缓存来达到减轻数据库压力的目的,或者增加数据库数量来达到平滑的系统扩容。因此单用户系统设计重点在于灵活性和结构化。
5张表的设计
列举一下一个blog系统需要哪些元素,这样也可以让我们更好地设计数据库表。除了文章、评论、分类、用户、链接外,还有文件、标签、链接分类、多重分类。如果考虑到系统的灵活性,还需要将所有的可配置选项放到一个表中,类似于wordpress的options表。清点一下这些表:
文章表
评论表
文章分类表
标签表
链接表(友情链接)
链接分类表
文章与分类映射表(一对多)
文章与标签映射表(一对多)
配置表
用户表
文件表
一共11张表,虽然不是很多但是总觉得还有抽象的余地。当仔细观察它们之间的关系后,除了配置表和用户表之外。其它表之间的关系都可以抽象为内容与项目之间的关系(可能是一对一,可能是一对多)。通过这个抽象,我们可以把剩下的表缩减为3个表,那么来看看我们的第二版数据库结构:
内容表
关系表
项目表
配置表
用户表
根据以上设计以及我们的经验,只需要精心设计内容表和项目表的表结构就可以形成丰富的扩展应用。项目表与内容表的对应形成了对内容的修饰。由于有了关系表的存在内容与项目的关系可以是一对一也可以是一对多。
6张表的设计
如果你仔细分析一下上面的设计,你会发现一个隐藏的问题,那就是评论表的定义。显然评论表不可能是项目表,那么他只可能是内容表,但内容与内容之间的关系是我们以上设计中所没有定义的。观察评论与内容的关系
评论从属于内容,无法单独存在
评论与内容是多对一的关系,且一条评论只能对应于一个内容
评论的数量往往比较大,对于访问量比较大的blog。其单篇文章的评论往往要达到上百篇。
根据以上考虑,评论表应该单独形成一个表与内容区分开。且根据常规做法以及速度上的考虑,评论应该用一个保留字段保存其从属内容的主键以便查询。那么第三版数据库结构就出炉了。
内容表
关系表
项目表
评论表
配置表
用户表
梳理设计
内容表可以扩展出来的类型
post(文章)
draft(草稿)
page(页面)
link(链接)
attachment(文件)
项目表里的类型
category(分类)
tag(标签)
link_category(链接分类)
表以及字段命名
考虑到标准化和国际化的需要,在表以及字段设置上应该尽量使用标准名称。而由于使用了一对多的关系映射,在可以预见的地方内容与项目之间都不可能使用联合查询,而是用多次*联动查询*,来取出多行关联数据。所以内容表与项目表的字段是可以重名的(在联合查询中,重名字段会被覆盖)。以下是对各数据表的命名:
内容表 – contents
关系表 – relationships
项目表 – metas (meta的意思为关于什么的什么)
评论表 – comments
配置表 – options
用户表 – users
Typecho数据字典
contents表
键名 | 类型 | 属性 | 解释 |
cid | int(10) | 主键,非负,自增 | post表主键 |
title | varchar(200) | 可为空 | 内容标题 |
slug | varchar(200) | 索引,可为空 | 内容缩略名 |
created | int(10) | 索引,非负,可为空 | 内容生成时的GMT unix时间戳 |
modified | int(10) | 非负,可为空 | 内容更改时的GMT unix时间戳 |
text | text | 可为空 | 内容文字 |
order | int(10) | 非负,可为空 | 排序 |
authorId | int(10) | 非负,可为空 | 内容所属用户id |
template | varchar(32) | 可为空 | 内容使用的模板 |
type | varchar(16) | 可为空 | 内容类别 |
status | varchar(16) | 可为空 | 内容状态 |
password | varchar(32) | 可为空 | 受保护内容,此字段对应内容保护密码 |
commentsNum | int(10) | 非负,可为空 | 内容所属评论数,冗余字段 |
allowComment | char(1) | 可为空 | 是否允许评论 |
allowPing | char(1) | 可为空 | 是否允许ping |
allowFeed | char(1) | 可为空 | 允许出现在聚合中 |
relationships表
键名 | 类型 | 属性 | 解释 |
cid | int(10) | 主键,非负 | 内容主键 |
mid | int(10) | 主键,非负 | 项目主键 |
metas表
键名 | 类型 | 属性 | 解释 |
mid | int(10) | 主键,非负 | 项目主键 |
name | varchar(200) | 可为空 | 名称 |
slug | varchar(200) | 索引,可为空 | 项目缩略名 |
type | varchar(32) | 可为空 | 项目类型 |
description | varchar(200) | 可为空 | 选项描述 |
count | int(10) | 非负,可为空 | 项目所属内容个数 |
order | int(10) | 非负,可为空 | 项目排序 |
comments表
键名 | 类型 | 属性 | 解释 |
coid | int(10) | 主键,非负,自增 | comment表主键 |
cid | int(10) | 索引,非负 | post表主键,关联字段 |
created | int(10) | 非负,可为空 | 评论生成时的GMT unix时间戳 |
author | varchar(200) | 可为空 | 评论作者 |
authorId | int(10) | 非负,可为空 | 评论所属用户id |
ownerId | int(10) | 非负,可为空 | 评论所属内容作者id |
varchar(200) | 可为空 | 评论者邮件 | |
url | varchar(200) | 可为空 | 评论者网址 |
ip | varchar(64) | 可为空 | 评论者ip地址 |
agent | varchar(200) | 可为空 | 评论者客户端 |
text | text | 可为空 | 评论文字 |
type | varchar(16) | 可为空 | 评论类型 |
status | varchar(16) | 可为空 | 评论状态 |
parent | int(10) | 可为空 | 父级评论 |
options表
键名 | 类型 | 属性 | 解释 |
name | varchar(32) | 主键 | 配置名称 |
user | int(10) | 主键,非负 | 配置所属用户,默认为0(全局配置) |
value | text | 可为空 | 配置值 |
users表
键名 | 类型 | 属性 | 解释 |
uid | int(10) | 主键,非负,自增 | user表主键 |
name | varchar(32) | 唯一 | 用户名称 |
password | varchar(32) | 可为空 | 用户密码 |
varchar(200) | 唯一 | 用户的邮箱 | |
url | varchar(200) | 可为空 | 用户的主页 |
screenName | varchar(32) | 可为空 | 用户显示的名称 |
created | int(10) | 非负,可为空 | 用户注册时的GMT unix时间戳 |
activated | int(10) | 非负,可为空 | 最后活动时间 |
logged | int(10) | 非负,可为空 | 上次登录最后活跃时间 |
group | varchar(16) | N/A | 用户组 |
authCode | varchar(40) | 可为空 | 用户登录验证码 |