mysql菜鸟教程
10.4 第三范式(3NF)
经过第一范式和第二范式的洗礼,我们的表已经消除了数据冗余的大部分隐患,但仍然可能存在一种隐藏的问题——传递依赖。第三范式(3NF)正是为了解决这一问题而诞生的。它是实际项目中最常用的范式级别,通常达到3NF就认为数据库设计已经足够规范。
一、什么是传递依赖?
在理解第三范式之前,我们需要先搞清楚传递函数依赖的概念。
传递依赖是指:如果存在函数依赖 X → Y 和 Y → Z,并且 Y 不依赖于 X(即 Y 不是 X 的子集),那么称 Z 传递依赖于 X。简单来说,就是通过中间属性 Y,间接地确定了 Z。
例如:学号 → 学院编号,学院编号 → 学院名称,那么学号 → 学院名称就是传递依赖(学号间接决定了学院名称)。
传递依赖会导致数据冗余和更新异常,即使表已经满足2NF,这些问题依然可能存在。
二、一个不符合3NF的典型例子
假设我们有一个学生表,记录了学生的基本信息以及所属学院的信息:
分析:
候选键:student_id(单列主键,因此自动满足2NF)。
主属性:student_id
非主属性:student_name, college_id, college_name, college_address
函数依赖关系:
student_id → student_name(直接依赖)
student_id → college_id(直接依赖)
college_id → college_name(学院ID决定学院名称)
college_id → college_address(学院ID决定学院地址)
因此,存在传递依赖:student_id → college_id → college_name,以及 student_id → college_id → college_address。
存在的问题
数据冗余:同一个学院的信息(学院名称、地址)在每个学生记录中重复存储。
更新异常:如果学院名称更改(例如“计算机学院”改名为“信息学院”),需要更新所有相关学生的记录,否则会不一致。
插入异常:如果要新增一个学院,但还没有学生属于该学院,就无法插入学院信息(因为学生ID是主键,不能为空)。
删除异常:如果删除某个学院的最后一个学生,该学院的信息也会从数据库中消失。
这些问题与2NF中的部分依赖问题类似,但根源在于传递依赖,即非主属性依赖于另一个非主属性,而不是直接依赖于主键。
三、如何转换为3NF?
解决传递依赖的方法依然是拆分表:将那些依赖于非主属性的列移到新的表中,使每个非主属性都直接依赖于主键,而不是通过中间属性间接依赖。
对于上面的学生表,我们可以拆分成两张表:
学院表(colleges):
学生表(students):
现在:
students 表中的所有非主属性(student_name, college_id)都直接依赖于主键 student_id,没有传递依赖。
colleges 表中的所有非主属性(college_name, college_address)都直接依赖于主键 college_id。
这两张表都满足第三范式。
四、第三范式的完整定义
一个关系模式 R 属于第三范式(3NF),当且仅当它属于第二范式(2NF),并且不存在非主属性对候选键的传递函数依赖。
换句话说,3NF 要求每一个非主属性都不传递依赖于候选键,即每个非主属性必须直接依赖于候选键,而不能依赖于其他非主属性。
五、练习与思考
练习1
考虑一个订单表 orders:
这个表是否符合3NF?如果不符合,请分解。
分析:
候选键:order_id
非主属性:customer_id, customer_name, customer_phone, order_date, total_amount
函数依赖:
order_id → customer_id
customer_id → customer_name, customer_phone(假设一个客户只有一个名字和电话)存在传递依赖:order_id → customer_id → customer_name 和 customer_phone,因此不符合3NF。
分解:
客户表 customers:customer_id, customer_name, customer_phone
订单表 orders:order_id, customer_id, order_date, total_amount
练习2
如果一个表的主键是单列,且表中没有其他候选键,它是否一定满足3NF?
答案:不一定。虽然它满足2NF(单列主键自动满足),但仍可能存在传递依赖,如上面的例子所示。所以单列主键的表也需要检查传递依赖。
六、3NF 的意义
3NF 是规范化设计中最常用的目标,因为它:
基本消除了数据冗余和更新异常。
保持了数据的完整性和一致性。
在大多数业务场景下,达到了良好的平衡——既减少了冗余,又不会导致过多的表拆分(过度拆分可能导致查询复杂化)。
达到3NF后,通常可以说数据库设计是规范化的。但在某些特殊场景(如多值依赖、连接依赖)下,可能还需要考虑更高的范式(BCNF、4NF、5NF),不过这些在实践中的应用较少。
七、总结
第三范式(3NF) 在2NF的基础上,要求消除非主属性对候选键的传递依赖。
传递依赖是指通过中间属性间接决定另一个非主属性。
解决传递依赖的方法是将中间属性和它所决定的属性拆分到新表中。
达到3NF的表基本消除了数据冗余和更新异常,是实际项目中最常用的规范化级别。

发表评论
所有评论