1,数据库三范式我们可以从字段——列——表的维度来理解
第一范式:(确保每列保持原子性)
字段是不可再拆分的,即满足字段的原子性。比如,我们可以设计某一字段,字段名:地点,值的组成显示为省+市,比如:
表一:人员信息表
姓名 | 性别 | 年龄 | 出生地 |
张三 | 男 | 25 | 安徽安庆 |
李丽 | 女 | 23 | 浙江杭州 |
比如安徽安庆,若是取值省份,还要对取出来的字段再拆分。这就是不满足字段的原子性。为了满足范式一的话,就要拆分如下字段。
表二:学生信息表
学生ID | 姓名 | 性别 | 年龄 | 出生省份 | 出生市名 |
001 | 张三 | 男 | 18 | 安徽 | 安庆 |
002 | 李丽 | 女 | 17 | 浙江 | 杭州 |
第二范式(确保表中的每列都和主键相关,消除部分依赖。)
第二范式必须在第一范式基础上。确保数据库的每一列都和主键相关。若是联合主键,确保和主键的全部字段而不是部分字段相关。
拿如下成绩表举例子
学生ID | 学生姓名 | 科目ID | 科目名字 | 考试成绩 |
001 | 张三 | 0101 | 语文 | 89 |
002 | 丽丽 | 0102 | 数学 | 90 |
考试成绩依赖于学生ID及科目ID,所以联合主键是(学生ID,科目ID)
但是学生姓名部分依赖于学生ID。同理,科目名字依赖于科目id,因此发生部分依赖。去掉学生姓名及科目名字字段。
学生ID | 科目ID | 考试成绩 |
001 | 0101 | 89 |
002 | 0102 | 90 |
单独生成学生信息表和科目信息表
学生ID | 学生姓名 | … |
001 | 张三 | … |
002 | 丽丽 | … |
科目ID | 科目名字 | … |
0101 | 语文 | … |
0102 | 数学 | … |
第三范式3NF(确保每个非主属性都和主键列直接相关,而不是间接相关,消除传递依赖,非主属性的依赖)
第三范式消除的是传递依赖,确保数据库表中的每个非主属性数据都和主键相关,而不是间接相关。间接相关既是传递依赖,非主键列 A 依赖于非主键列 B,非主键列 B 依赖于主键的情况。
OrderID | OrderDate | CustomerID | CustomerName | CustomerAddr |
0001 | 20180920 | 0101 | 张三 | 上海浦东 |
0002 | 20190203 | 0102 | 李四 | 上海杨浦 |
其中 OrderDate,CustomerID,CustomerName,CustomerAddr等非主键列都完全依赖于主键(OrderID),所以符合 2NF。
不过问题是 CustomerName,CustomerAddr直接依赖的是 CustomerID(非主键列),而不是直接依赖于主键,它是通过传递才依赖于主键,所以不符合 3NF。通过拆分Order和Customer表满足3NF。
Order表
OrderID | OrderDate | CustomerID |
0001 | 20180920 | 0101 |
0002 | 20190203 | 0102 |
Customer表
CustomerID | CustomerName | CustomerAddr |
0101 | 张三 | 上海浦东 |
0102 | 李四 | 上海杨浦 |
通过拆分【Order】为【Order】(OrderID,OrderDate,CustomerID)和【Customer】(CustomerID,CustomerName,CustomerAddr,CustomerCity)从而达到 3NF。
注意:
当然三范式最大的问题在于查询的时候要Join很多表,这会导致查询效率很低。这个时候基于性能考虑,我们需要违反三范式,适当的做冗余,达到提高查询效率的目的。注意这里反范式是适度的,必须为这种做法提供充分的理由。
https://blog.csdn.net/qingking520/article/details/52937728
BC范式-BCNF
每个属性都不传递依赖于R的候选键,那么称R为BCNF的模式。