跟着项目学sql(二) 三大范式

序号表名说明
1permission权限表
2user用户表
3menu栏目表
4news新闻表
5clicks浏览信息表


ER图如下,并没有创建外键约束,因此本文中所有的外键都是指【逻辑外键】:

我们在数据库表设计时,经常说好的设计最起码要遵循第三范式,那现在用三大范式来检验一下我们的设计

-------------------------------------------------------------------------------------------------------------

数据库三大范式

          设计关系数据库时,遵从不同的规范要求,设计出合理的关系型数据库,这些不同的规范要求被称为不同的范式,各种范式呈递次规范,越高的范式数据库冗余越小。

目前关系数据库有8种范式(1NF,2NF,3NF,BCNF,4NF,5NF,DKNF,6NF),每一级范式都是基于前一范式的基础上,例如符合2NF的关系模式,必定符合1NF。一般说来,只需满足第三范式(3NF)就行了。

第一范式:所有属性都是不可分割的原子值

事实上,在目前的DBMS中是不可能拆分属性的。相对于excel来说,mysql的表并没有行合并和列合并的功能,因此从字面意思来看,我们的表很难违反第一范式!

第一范式包括下列指导原则:

1)关系中每个记录的每个属性只能包含一个值;                 ps:无法做到像Excel那样每个记录包含多个值。

2)关系中的每个记录必须包含相同数量的值;                  ps:无法做到像Excel那样每个记录包含不同数量的值

3)关系中的每个记录一定不能相同。                                 ps:要有主键约束或者唯一约束

我们每个表都用非业务主键id列,内容是GUID做主键,符合1NF。

 

第二范式:在第一范式的基础上,要求非主属性都要和码有完全依赖关系 

这句话显然是针对复合主键联合主键来说的

1)复合主键:以clicks(id,ip,useragent,news_id,create_time)表为例,我们这里用了非业务主键id列,内容是GUID,避开了2NF。

为了研究2NF,我们删掉id列,再来看这个问题:

表的业务主键是(ip,news_id,create_time),即某ip在某时间浏览了某条新闻,而浏览器(useragent)是完全依赖于业务主键的,这符合2NF。如果我们在表中增加了一个news_title字段,那news_title是只依赖于news_id的,从而违反了2NF。

mysql中不应该使用具有实际意义的column 作为主键,这是因为主键列的值不建议进行修改。第一是因为主键列经常用作其他表的外键,如果某一表的主键被修改了,那牵一发而动全身。第二是考虑到经常更新的列不适合创建索引,这当然也包括mysql中的主键索引了。

这里我们的每个表都用GUID做主键,从而避免了使用复合主键,也避开了这种情况。

2)联合主键:

为了应对表间多对多的关系,需要创建中间表,在NewsDB中,权限表(permission)和用户表(user)就是多对多的关系。

创建中间表

permission_user(permission_id,user_id,create_time)

(permission_id,user_id)就是联合主键,如果这时候在要表中添加username列,那就违反了2NF,

真实的项目中,我们在user表中用了一个permission字段存储用户权限id,把用户的多个权限id用逗号隔开,从而免去了中间表,避免了违反第二范式的可能。这种做法能够成立,主要原因是权限的数量比较固定,而且后台用户数量很小。事实上我们每次对权限表的删除操作,要去更新所有的用户的permission字段,用以去除脏数据,这在用户量多的情况下,是很失败的做法。

比如,我们的新闻表(news)中同样有一个menus字段,用来存储新闻所属的栏目id,多个栏目id用逗号隔开。这里也没有采用中间表,就是很严重的设计问题了!我们应该使用中间表news_menus(id,news_id,menu_id)

除了上面讲的脏数据处理的问题,更主要的还是前台的查询性能问题,相比之下后台的所有功能都应该给它让路。要显示某栏目下的新闻,直接去中间表中查找对应的menu_id,即可筛选出所有的news_id,这变相的起到了索引表的效果。

反观是原来的方式,menus字段里多个栏目id用逗号隔开,我们就只能在where条件中用mysql中的locate()函数了(类似indexOf的功能),这显然是不能接受的。

这里添加中间表news_menus(id,news_id,menu_id)

 

第三范式:任何非主属性不依赖于其它非主属性。 

           这显然是针对外键来说的,这里以News表为例:

news(id,title,keywords,...,user_id,username,...state),username依赖于user_id,从而在表面上违反了第三范式。这里多存一个username主要是为了在用户被删除的情况下,还能取到用户名。这关系到后面的报表统计问题和应对可能发生的薪酬纠纷。

如果用户被删除,同时news表里只有一个user_id,那username就无从查起了。也就是说,现在即使把user表中的记录删除,news表中的username仍不受影响,这已经说明news表中的username字段并不依赖于user_id,因此这里并没有违反3NF。

我们还是以上面刚刚添加的新闻菜单表中间表news_menus(id,news_id,menu_id)为例,如果这时候在要表中添加news_title列,则违反了3NF

 

第二范式和第三范式的区别:

2NF针对复合主键和联合主键,表中属性存在部分依赖

3NF针对外键,在满足2NF的基础上,表中属性依赖于外键,造成传递依赖。

记住:

news_menus(news_id,menu_id,news_title)       违反2NF,部分依赖

news_menus(id,news_id,menu_id,news_title)    违反3NF,传递依赖

一般的在mysql都会用非业务主键,避开了部分依赖,反而造成了传递依赖出现的概率比较大!

-----------------------------------------------------------------------------------------------------------------------------------------------------------------

最后修订的数据库: 

序号表名说明
1permission权限表
2user用户表
3menu栏目表
4news新闻表
5news_menus新闻_栏目表
6clicks浏览信息表

 

1、表名:permission(权限表)

序号名称数据类型长度小数位允许空值主键默认值说明
1idvarchar(45)450NY 主键
2namevarchar(45)450Y  权限名称
3orderbyint100Y 0排序
4create_timedatetime230Y CURRENT_TIMESTAMP创建时间

 

2、表名:user(用户表)

序号名称数据类型长度小数位允许空值主键默认值说明
1idvarchar(45)450NY 主键
2usernamevarchar(45)450N  用户名
3passwordvarchar(45)450N  密码
4permissionvarchar(200)2000Y  

权限id

(多个用逗号隔开)

5create_timedatetime230Y CURRENT_TIMESTAMP创建时间

 

3、表名:menu(栏目表)

序号名称数据类型长度小数位允许空值主键默认值说明
1idvarchar(45)450NY  
2namevarchar(45)450N  栏目名称
3urlvarchar(200)2000N  栏目url
4orderbyint100Y 0排序字段
5create_timedatetime230Y CURRENT_TIMESTAMP创建时间

 

4、表名:news(新闻表)

序号名称数据类型长度小数位允许空值主键默认值说明
1idvarchar(45)450NY 主键
2titlevarchar(200)2000N  标题
3keywordsvarchar(200)2000Y  关键词
4menusvarchar(200)2000N  所属栏目(逗号隔开)
5authorvarchar(45)450N  新闻来源
6thumbvarchar(200)2000Y  缩略图
7contenttext655350N  新闻内容
8user_idvarchar(45)450Y  创建人id
9usernamevarchar(45)450Y  创建人
10create_timedatetime230Y CURRENT_TIMESTAMP创建时间
11edit_timedatetime230Y  最后编辑时间
12statetinyint10N 0

        新闻状态

(0未发布1已发布)

 

5、表名:news_menus(新闻_栏目表)

序号名称数据类型长度小数位允许空值主键默认值说明
1idvarchar(45)450NY  
2news_idvarchar(45)450N   
3menu_idvarchar(45)450N   

 

 

6、表名:clicks(浏览信息表)

序号名称数据类型长度小数位允许空值主键默认值说明
1idvarchar(45)450NY  
2ipvarchar(45)450N  浏览人ip地址
3useragentvarchar(500)5000Y  浏览器useragent
4news_idvarchar(45)450N  新闻id
5create_timedatetime230Y CURRENT_TIMESTAMP创建时间

 

 

 

 

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值