mysql菜鸟教程

专栏导航

10.4 第三范式(3NF)

      经过第一范式和第二范式的洗礼,我们的表已经消除了数据冗余的大部分隐患,但仍然可能存在一种隐藏的问题——传递依赖。第三范式(3NF)正是为了解决这一问题而诞生的。它是实际项目中最常用的范式级别,通常达到3NF就认为数据库设计已经足够规范。

一、什么是传递依赖?

在理解第三范式之前,我们需要先搞清楚传递函数依赖的概念。

传递依赖是指:如果存在函数依赖 X → Y 和 Y → Z,并且 Y 不依赖于 X(即 Y 不是 X 的子集),那么称 Z 传递依赖于 X。简单来说,就是通过中间属性 Y,间接地确定了 Z。

例如:学号 → 学院编号,学院编号 → 学院名称,那么学号 → 学院名称就是传递依赖(学号间接决定了学院名称)。

传递依赖会导致数据冗余和更新异常,即使表已经满足2NF,这些问题依然可能存在。

二、一个不符合3NF的典型例子

假设我们有一个学生表,记录了学生的基本信息以及所属学院的信息:

student_id

student_name

college_id

college_name

college_address

1

张三

C01

计算机学院

科技楼A座

2

李四

C01

计算机学院

科技楼A座

3

王五

C02

管理学院

行政楼B座

分析

  • 候选键:student_id(单列主键,因此自动满足2NF)。

  • 主属性:student_id

  • 非主属性:student_namecollege_idcollege_namecollege_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

存在的问题

  1. 数据冗余:同一个学院的信息(学院名称、地址)在每个学生记录中重复存储。

  2. 更新异常:如果学院名称更改(例如“计算机学院”改名为“信息学院”),需要更新所有相关学生的记录,否则会不一致。

  3. 插入异常:如果要新增一个学院,但还没有学生属于该学院,就无法插入学院信息(因为学生ID是主键,不能为空)。

  4. 删除异常:如果删除某个学院的最后一个学生,该学院的信息也会从数据库中消失。

这些问题与2NF中的部分依赖问题类似,但根源在于传递依赖,即非主属性依赖于另一个非主属性,而不是直接依赖于主键。

三、如何转换为3NF?

解决传递依赖的方法依然是拆分表:将那些依赖于非主属性的列移到新的表中,使每个非主属性都直接依赖于主键,而不是通过中间属性间接依赖。

对于上面的学生表,我们可以拆分成两张表:

学院表(colleges)

college_id

college_name

college_address

C01

计算机学院

科技楼A座

C02

管理学院

行政楼B座

学生表(students)

student_id

student_name

college_id

1

张三

C01

2

李四

C01

3

王五

C02

现在:

  • students 表中的所有非主属性(student_namecollege_id)都直接依赖于主键 student_id,没有传递依赖。

  • colleges 表中的所有非主属性(college_namecollege_address)都直接依赖于主键 college_id

这两张表都满足第三范式。

四、第三范式的完整定义

一个关系模式 R 属于第三范式(3NF),当且仅当它属于第二范式(2NF),并且不存在非主属性对候选键的传递函数依赖

换句话说,3NF 要求每一个非主属性都不传递依赖于候选键,即每个非主属性必须直接依赖于候选键,而不能依赖于其他非主属性。

五、练习与思考

练习1

考虑一个订单表 orders

order_id

customer_id

customer_name

customer_phone

order_date

total_amount

1

1001

张三

13800138000

2024-01-01

299.00

2

1002

李四

13900139000

2024-01-02

159.00

3

1001

张三

13800138000

2024-01-03

89.00

这个表是否符合3NF?如果不符合,请分解。

分析

  • 候选键:order_id

  • 非主属性:customer_idcustomer_namecustomer_phoneorder_datetotal_amount

  • 函数依赖:

    • order_id → customer_id

    • customer_id → customer_namecustomer_phone(假设一个客户只有一个名字和电话)存在传递依赖:order_id → customer_id → customer_name 和 customer_phone,因此不符合3NF。

分解

  • 客户表 customerscustomer_idcustomer_namecustomer_phone

  • 订单表 ordersorder_idcustomer_idorder_datetotal_amount

练习2

如果一个表的主键是单列,且表中没有其他候选键,它是否一定满足3NF?

答案:不一定。虽然它满足2NF(单列主键自动满足),但仍可能存在传递依赖,如上面的例子所示。所以单列主键的表也需要检查传递依赖。

六、3NF 的意义

3NF 是规范化设计中最常用的目标,因为它:

  • 基本消除了数据冗余和更新异常。

  • 保持了数据的完整性和一致性。

  • 在大多数业务场景下,达到了良好的平衡——既减少了冗余,又不会导致过多的表拆分(过度拆分可能导致查询复杂化)。

达到3NF后,通常可以说数据库设计是规范化的。但在某些特殊场景(如多值依赖、连接依赖)下,可能还需要考虑更高的范式(BCNF、4NF、5NF),不过这些在实践中的应用较少。

七、总结

  • 第三范式(3NF) 在2NF的基础上,要求消除非主属性对候选键的传递依赖。

  • 传递依赖是指通过中间属性间接决定另一个非主属性。

  • 解决传递依赖的方法是将中间属性和它所决定的属性拆分到新表中。

  • 达到3NF的表基本消除了数据冗余和更新异常,是实际项目中最常用的规范化级别。


发表评论

昵称:
联系方式:
评论内容:

所有评论

关于我 备案号:蜀ICP备2023042032号-1