> 技术文档 > MySQL 的三大范式详细介绍_mysql 第二范式

MySQL 的三大范式详细介绍_mysql 第二范式


文章目录

      • 1、第一范式(1NF):原子性
      • 2、第二范式(2NF):消除部分依赖
      • 3、第三范式(3NF):消除传递依赖
      • 4、三大范式总结
      • 4、如何判断数据库设计是否符合第三范式?
        • 1)确认已满足前两范式
        • 2、检查是否存在“传递依赖”
        • 3、示例分析
          • 反例(违反3NF)
          • 正例(符合3NF)
        • 4、常见误区与注意事项
        • 5、判断是否符合第三范式的核心流程:

MySQL(关系型数据库)的三大范式是数据库设计的基本准则,用于指导如何合理组织表结构,目的是减少数据冗余保证数据一致性。遵循范式可以让数据库设计更严谨、维护更高效。

1、第一范式(1NF):原子性

核心要求:表中所有字段的值都必须是不可分割的原子值(即最小单位,不能再拆分)。

解读

  • 不能有复合字段(如“地址”字段不能同时存储“省+市+区”,需拆分为单独字段)。
  • 不能有重复的列或多值字段(如“电话”字段不能存储多个号码,应拆分为多行或单独表)。

反例(不满足1NF):

id name address 1 张三 北京市朝阳区,100000

正例(满足1NF):

id name city district zip_code 1 张三 北京市 朝阳区 100000

2、第二范式(2NF):消除部分依赖

前提:必须先满足第一范式(1NF)。
核心要求:表中主键字段必须完全依赖于整个主键,而不能只依赖于主键的一部分(针对复合主键)。

解读

  • 若表的主键是单一字段(如 id),则自动满足2NF(因为没有“部分依赖”的可能)。
  • 若主键是复合主键(如 (student_id, course_id)),则其他字段(如 scorestudent_name)必须依赖于整个 (student_id, course_id),而不能只依赖于 student_id(如 student_name 只依赖 student_id,属于部分依赖,需拆分)。

反例(不满足2NF):
| student_id(主键) | course_id(主键) | student_name | score | (复合主键:student_id+course_id)
|-------------------|------------------|--------------|-------|
| 101 | 201 | 李四 | 90 | (student_name 只依赖 student_id,属于部分依赖)

正例(满足2NF):

  1. 拆分出学生表(独立存储学生信息):

    student_id(主键) student_name 101 李四
  2. 成绩表(只保留依赖于复合主键的字段):

    student_id(主键) course_id(主键) score 101 201 90

3、第三范式(3NF):消除传递依赖

前提:必须先满足第二范式(2NF)。
核心要求:表中非主键字段之间不能存在依赖关系(即非主键字段必须直接依赖于主键,而不能依赖于其他非主键字段)。

解读

  • 禁止“非主键A → 非主键B”的传递依赖(A和B都不是主键,但B的值由A决定)。
  • 需将传递依赖的字段拆分到新表中,通过主键关联。

反例(不满足3NF):
| order_id(主键) | product_id | product_name | price | (product_name和price依赖于product_id,而非主键order_id,形成传递依赖)
|-----------------|------------|--------------|-------|

正例(满足3NF):

  1. 订单表(只保留与订单直接相关的字段):

    order_id(主键) product_id quantity 5001 1001 2
  2. 商品表(独立存储商品信息):

    product_id(主键) product_name price 1001 笔记本电脑 5999

4、三大范式总结

三大范式的核心目标是**“去冗余”**,但并非必须严格遵守:

  • 遵循的好处:数据一致性高,更新/删除时不易出现异常(如修改商品名时只需改一次)。
  • 灵活处理:实际设计中可能为了查询效率适当保留冗余(如“反范式设计”),需在冗余和性能之间平衡。

简单记忆:
1NF → 字段不可拆;
2NF → 非主键依赖整个主键;
3NF → 非主键之间无依赖。

4、如何判断数据库设计是否符合第三范式?

判断数据库设计是否符合第三范式(3NF),需要基于其核心要求:在满足第二范式(2NF)的前提下,表中的非主键字段必须直接依赖于主键,且不存在非主键字段之间的传递依赖(即“非主键A → 非主键B”的依赖关系)。

具体判断步骤和方法如下:

1)确认已满足前两范式

第三范式是建立在第二范式基础上的,因此需先验证:

  1. 是否满足1NF:所有字段的值都是不可分割的原子值(无复合字段、多值字段)。
  2. 是否满足2NF:非主键字段必须完全依赖于整个主键(对复合主键而言,不能只依赖主键的一部分)。

若不满足前两范式,无需判断3NF,需先优化至符合2NF。

2、检查是否存在“传递依赖”

传递依赖的定义:
在表中,若存在 “主键 → 非主键A → 非主键B” 的关系(即B依赖于A,而A依赖于主键),则B传递依赖于主键,违反3NF。

判断方法
对表中每个非主键字段,问两个问题:

  1. 这个字段是否直接依赖于主键?(即能否通过主键唯一确定该字段的值?)
  2. 这个字段是否依赖于表中的其他非主键字段?(即是否存在“非主键A决定非主键B”的情况?)

若存在任何非主键字段依赖于其他非主键字段(而非直接依赖于主键),则违反3NF。

3、示例分析
反例(违反3NF)

假设有一个 orders 表(订单表):

字段名(主键:order_id) 含义 依赖关系分析 order_id 订单ID 主键 product_id 商品ID 依赖主键(每个订单关联一个商品) product_name 商品名称 依赖于 product_id(而非直接依赖主键) product_price 商品单价 依赖于 product_id(而非直接依赖主键) quantity 购买数量 直接依赖主键(订单决定购买数量)

问题
product_nameproduct_price 依赖于 product_id(非主键),而 product_id 依赖于主键 order_id,形成传递依赖(order_id → product_id → product_name),因此违反3NF。

正例(符合3NF)

拆分后的表结构:

  1. 订单表(orders)
字段名(主键:order_id) 含义 依赖关系分析 order_id 订单ID 主键 product_id 商品ID 依赖主键(关联商品) quantity 购买数量 直接依赖主键
  1. 商品表(products)
字段名(主键:product_id) 含义 依赖关系分析 product_id 商品ID 主键 product_name 商品名称 直接依赖主键 product_price 商品单价 直接依赖主键

为什么符合3NF

  • 订单表中,所有非主键字段(product_idquantity)均直接依赖于主键 order_id
  • 商品表中,所有非主键字段(product_nameproduct_price)均直接依赖于主键 product_id
  • 不存在非主键字段之间的依赖关系,消除了传递依赖。
4、常见误区与注意事项
  1. “直接依赖” vs “间接依赖”
    3NF允许非主键字段“间接关联”主键(如通过外键关联其他表的主键),但不允许在同一张表内通过其他非主键字段间接依赖主键。

  2. 允许合理的冗余
    实际设计中,为了查询效率可能会保留少量冗余(反范式设计),但这并不影响对3NF的判断——判断是否符合3NF是“是否存在传递依赖”,而非“是否完全无冗余”。

  3. 复合主键的情况
    即使主键是复合主键(如 (A,B)),只要非主键字段仅依赖于 (A,B) 整体,且不依赖于其他非主键字段,仍符合3NF。

5、判断是否符合第三范式的核心流程:
  1. 确保满足1NF和2NF;
  2. 检查表中是否存在“非主键A → 非主键B”的传递依赖;
  3. 若不存在传递依赖,则符合3NF;反之则不符合,需拆分表消除传递依赖。

通过这种方式,可以保证数据的逻辑清晰,减少更新异常(如修改商品名称时,只需在商品表中修改一次,而非所有关联订单表)。