设计数据库的六大范式

最近新项目启动,后端需要重新设计数据库。老师傅将这个任务交给了新人,并提醒新人要注意设计数据库的三大范式。
第一个听到这个概念,于是就顺便学习一下。

一、什么是范式

范式说白了就是数据库表格的一些设计规范。

二、为什么需要范式

遵循范式设计规范的数据库,可以有效避免数据冗余,减少数据库空间,减轻维护数据库完整性的麻烦。

三、范式的问题

过于深入地去遵守范式反而会让操作变得困难,需要联系多个表才能得到想要所需要的数据。
为了拿到想要的数据,需要反复查询表格,对硬盘I/O速度有较高的要求,这在高并发性的情景下非常不好使。
因此范式等级越高,其性能就越差。
一般项目中,第三范式已经够用了。因此本文只总结前三个范式,后面的暂时不管。

四、有哪些范式

目前比较常说的范式一共有六个,即1NF、2NF、3NF、BC范式(巴斯科德范式)、4NF、5NF。
这些范式是层层递进的,也就是说要实现后一个范式的规范,是需要遵循之前所有范式的规范。

在了解范式之前,需要明确几个概念:

  • 函数依赖:如果一个表中的字段Y是由另外一个字段X或一组字段X的值来决定的, 那么就可以说Y函数依赖于X。
  • 候选键:我的理解是可以用来作为查询表格的最小字段组合就是一个候选键。比如一张学生表(学号、姓名、性别、身份证号、教师编号),其中学号、身份证号就是这个表的候选键
  • 主键:又称主关键字或主码,我们一般可以将候选键中的某一个人为设置为主键,比如学生表,我可设置学号为主键,也可以设置身份证号为主键。

1. 第一范式(1NF)

当表格中的所有属性都具有原子性,无法再被分割,那么我们就可以说这个表格遵循了第一范式

比如,下面这个学生信息表格:

学生编号 姓名 性别 联系方式
20080901 张三 email:zs@126.com,phone:88886666
20080902 李四 email:ls@126.com,phone:66668888

联系方式里面既可以保存邮箱,又可以保存电话号码,那么我们就可以将它拆开,以此来遵循第一范式:

学生编号 姓名 性别 邮箱 电话号码
20080901 张三 email:zs@126.com phone:88886666
20080902 李四 email:ls@126.com phone:66668888

2. 第二范式(2NF)

表格中的所有非主属性都完全函数依赖于候选键,而不是部分依赖,那这个表格就符合第二规范。

比如下面这一张学生选课表:

学生 课程 教师 教师职称 教材 教室 上课时间
李四 Spring 张老师 java讲师 《Spring深入浅出》 301 08:00
张三 Struts 杨老师 java讲师 《Struts in Action》

这里可以通过(学生,课程)来确定(教师,教师职称,教材,教师,上课时间),所以我们可以把(学生,课程)作为主键。
但是其中教材不完全依赖于(学生,课程),其实只要知道课程,我们就可以确定教材了。
这就是不完全依赖,也就是部分依赖,当出现这种情况时,就不符合2NF了。

因此我们可以将课程和教材拿出来单独做一张表,像这样:

  • 学生选课表

    学生 课程 教师 教师职称 教室 上课时间
    李四 Spring 张老师 java讲师 301 08:00
    张三 Struts 杨老师 java讲师 302 13:30
  • 课程表

    课程 教材
    Spring 《Spring深入浅出》
    Struts 《Struts

也就是将原来学生选课表的教材列抽离出来,单独与课程做成课程表,这样出来的表格消除了部分依赖,符合2NF规范。
2NF可以减少插入异常、删除异常以及修改异常

3. 第三范式(3NF)

当非主属性之间存在函数依赖,也就是传递依赖,那么这个表就不符合3NF。

比如上面的学生选课表,教师依赖于(学生,课程),而教师职称又依赖于(教师),这样就形成了传递依赖。

于是需要经过以下修改:

  • 选课表

    学生 课程 教师 教室 上课时间
    李四 Spring 张老师 301 08:00
    张三 Struts 杨老师 302 13:30
  • 教师表

    教师 教师职称
    张老师 java讲师
    杨老师 java讲师

这样教师跟职称就有地方存了,不会因为没有学生选他们的课,导致他们完全消失不见了。
另外当教师的职称发生变化时,也不需要一个个去修改了。

总的来说,以上三个范式对数据库表格的设计要求就是原子性完全依赖以及没有传递依赖

参考
数据库设计的六大范式(不断修正)


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!