跳至主要内容

什么是第二范式(2NF)?

了解第二范式(2NF)如何通过消除部分依赖来改进您的数据库设计。
· 9分钟 阅读

使用 AI 探索

在处理数据库时,常会遇到数据冗余和更新不一致等问题。第二范式是建立在第一范式(1NF)之上的数据库规范化步骤,用于构建更整洁、更高效的表。

对于从事数据库设计或数据管理的任何人来说,理解 2NF 至关重要,它也为更高阶的规范化形式(如第三范式,3NF)打下基础。本文将通过实际示例介绍 2NF 的工作原理以及如何将表格转换为满足 2NF 要求。我们还会讨论 2NF 的优缺点以及其最适用的场景。

理解第二范式

第二范式是以消除部分依赖为核心的数据库规范化步骤。它由关系型数据库的先驱 Edgar F. Codd 在其规范化研究中提出。

一张表要达到 2NF,必须首先满足第一范式的规则:

  • 原子性: 每个单元格只能包含一个值(不能有重复组或数组)。
  • 行唯一: 表必须有明确的主键。

在此基础上,2NF 还要求:消除部分依赖。

当某个非主属性(不属于任何候选键的列)仅依赖于复合键的一部分而非整个键时,就发生了部分依赖。2NF 规则确保所有非主属性都依赖于完整的主键,而不是其中某一部分。如果在表中保留部分依赖,冗余数据就可能渗入数据库,导致低效,并在更新或删除时引发潜在不一致。

光讲理论可能有点枯燥,我们来看一个实际例子。

下面是 DataCamp 学生的课程选课表。

学生 ID课程 ID课程名称讲师姓名
1001201SQL FundamentalsKen Smith
1002202Introduction to PythonMerlin O’Donnell
1001202Introduction to PythonMerlin O’Donnell

这里,主键是学生 ID与课程 ID的复合。然而,非主属性课程名称和课程费用仅依赖于课程 ID,而不是整个键。这违反了 2NF。

分解表以实现 2NF 的步骤

要确保一张表遵循 2NF 的规则,您需要:

  1. 识别所有候选键: 确定能唯一标识表中行的最小属性集。这些就是候选键。
  2. 确定函数依赖: 识别表中的所有函数依赖。特别关注那些非主属性(不属于任何候选键)仅依赖于复合键部分而非整个键的依赖关系。
  3. 消除部分依赖: 对每个部分依赖:
    • 将受其影响的属性与它们所依赖的键部分一起移动到新表中。
    • 确保新表有唯一的主键。
  4. 重复直到不再存在部分依赖: 确认所有表中的每个非主属性都完全依赖其各自的主键。

第二范式的实践示例

现在我们来看两个示例。

示例 1:课程选课表

前面我们看到如下选课表:

学生 ID课程 ID课程名称讲师姓名
1001201SQL FundamentalsKen Smith
1002202Introduction to PythonMerlin O’Donnell
1001202Introduction to PythonMerlin O’Donnell

我们按照上一节的步骤来操作。

1. 识别候选键

在该表中,候选键是由学生 ID与课程 ID组成的复合键。这个唯一的组合可以标识表中的每一行。

2. 确定函数依赖

课程名称和讲师姓名依赖于课程 ID,而不是完整的复合键(学生 ID,课程 ID)。这属于部分依赖,因为这些属性只依赖于复合键的一部分。

3. 消除部分依赖

我们需要将只依赖键部分的属性(课程名称和讲师姓名)移动到一个仅基于课程 ID的新表中。

分解后,我们的新表如下:

课程选课表

学生 ID课程 ID
1001201
1002202
1001202

课程详情表

课程 ID课程名称讲师姓名
201SQL FundamentalsKen Smith
202Introduction to PythonMerlin O’Donnell

如果您想亲自动手创建自己的数据库,可以看看我们的 PostgresQL 课程。如果您已有一定基础,可以尝试这门 Introduction to Data Modeling in Snowflake,涵盖实体-关系和维度建模等主题。

示例 2:订单表

我们从这张订单表开始。试着按照上面的步骤自行分解这张表!

订单 ID产品 ID下单日期产品名称供应商名称
12012024-11-01LaptopTechSupply
12022024-11-01MouseTechSupply
22012024-11-02LaptopTechSupply
32032024-11-03KeyboardKeyMasters

1. 识别候选键

订单 ID与产品 ID的组合可以唯一标识每一行,因此(订单 ID,产品 ID)构成一个复合候选键。没有任何单列可以唯一标识行,因为:

  • 订单 ID 本身不唯一,因为同一订单可以包含多个产品。
  • 产品 ID 本身不唯一,因为同一产品可以出现在不同订单中。

这意味着(订单 ID,产品 ID)也是我们的主键。

2. 确定函数依赖

下单日期依赖于订单 ID(而非完整的复合键)。这属于部分依赖。

产品名称和供应商名称依赖于产品 ID(而非完整的复合键)。这些同样是部分依赖。

3. 消除部分依赖

我们需要将该表拆分为更小的表,每个表对应一个逻辑依赖。

首先,我们创建包含订单 ID专属信息的订单信息表。

订单表

订单 ID下单日期
12024-11-01
22024-11-02
32024-11-03

接着,我们创建一个包含产品 ID专属信息的表。

订单表

产品 ID产品名称供应商名称
201LaptopTechSupply
202MouseTechSupply
203KeyboardKeyMasters

原始表现在仅保留复合键以及订单与产品之间的关联关系。

订单 ID产品 ID
1201
1202
2201
3203

现在,我们的数据库已满足 2NF,因为 1)所有部分依赖都被消除;2)非主属性完全依赖各自的主键。

何时实施第二范式

那么,为什么要将数据库重构到 2NF?它本身是否足够,还是应该更进一步,目标指向 3NF?

第二范式的优势与局限

第二范式有多项优势,使其成为数据库规范化过程中有用的一步:

  • 提升数据完整性: 通过消除部分依赖,2NF 将插入、更新和删除异常降至最低,从而使数据库更可靠。
  • 减少冗余: 2NF 降低数据重复,优化存储使用并简化数据维护。
  • 改进数据结构: 为进一步规范化(如推进到第三范式)奠定基础,营造更整洁、更高效的数据库设计。

但它也有一些局限:

  • 复杂性增加: 为满足 2NF 而分解表会让设计过程更复杂,尤其是在涉及复合键和依赖关系时。
  • 额外的连接: 表拆分后,查询可能需要更多连接,在数据量大或查询复杂的系统中可能影响性能——下文会有更多讨论。
  • 残留冗余: 2NF 虽然减少部分依赖,但不处理传递依赖,仍会留下一些冗余,需在 3NF 中进一步解决。

第二范式的性能考量

为消除部分依赖而分解表会直接影响数据库性能。一方面,实现 2NF 可以减少数据冗余并提升一致性,从而在插入、更新或删除操作中更少出现异常。另一方面,规范化会增加表的数量,检索相关数据时需要额外的连接,这可能对大数据集中的查询性能造成影响。

为确保规范化后的数据库仍具备良好性能,请遵循以下最佳实践:

  • 索引: 使用索引加速分解表之间的连接。
  • 查询优化: 优化查询以尽量降低额外连接的成本。
  • 混合方法: 在性能关键的区域(如报表表)将规范化与反规范化结合使用。
  • 定期监控: 持续使用分析工具评估数据库性能,及时发现潜在问题。

2NF 只是迈向第三范式的过渡步骤吗?

在大多数情况下,数据库设计者会力求达到第三范式,因为它能进一步减少冗余并提升整体数据完整性。然而,实现 3NF 往往需要更多工作,例如创建更多的表和关系,这可能在查询执行中引入复杂性和性能权衡。

也有仅采用第二范式就足够的情况。如果以简洁和快速实施为优先,例如小型项目、原型阶段,或数据冗余极少的情形,2NF 可能已能满足需求。例如,在所有属性都已完全依赖于简单主键的系统中,实现 2NF 就能达成减少部分依赖的主要目标,而无需进一步规范化。

超越第二范式:迈向第三范式

如果您希望进一步规范化数据库,可以继续重构表直至达到第三范式。

3NF 建立在 2NF 之上,解决传递依赖——即非键属性依赖于其他非键属性而不是主键的情况。通过这种推进,确保每个属性都直接依赖于主键而非其他因素。

例如,在跟踪课程选课的表中:

  • 2NF:确保课程名称和学生姓名等属性完全依赖于各自的主键(如学生 ID与课程 ID)。这消除了非键属性仅依赖复合键部分的部分依赖。
  • 3NF:确保讲师详情或院系信息等存放于独立表中,消除传递依赖。

3NF 非常适合对数据完整性和效率有高要求的复杂系统,尤其是在数据量增长时。如果您想深入了解 3NF 及其更严格的形式 BCNF,欢迎阅读我们的文章 What is third normal form?。

结论

第二范式是数据库规范化中的关键一步,承上启下于 1NF 与更高阶的 3NF 等。通过去除部分依赖,2NF 能减少冗余并提升数据可靠性。尽管会带来一定复杂度,但其在提升数据完整性和简化维护方面的收益,使其成为高效数据库设计的重要组成部分。

如果您准备进一步提升技能,请探索我们的 Database Design 课程,深入理解规范化技术及其实际应用。您也可以通过我们的 SQL Associate Certification 来验证您的 SQL 与数据库管理技能,并向潜在雇主展示您的专业能力!

最后,如果您是企业的决策者,并且意识到需要构建更整洁、更高效的数据库,欢迎提交 DataCamp for Business 演示申请。我们可以帮助提升您团队的能力,以构建可扩展的数据库系统,推动业务效率与创新。我们甚至可以制定定制化学习路径和专属学习轨道。

Marie Fayard

作者

Marie Fayard

我是一名具有产品思维的技术负责人,专注于帮助早期初创公司从首个原型成长到实现产品与市场匹配,并持续向前发展。我对人们如何使用技术充满好奇,热爱与创始人及跨职能团队紧密合作,将大胆的想法变为现实。不在打造产品的时候,我会在世界的新角落寻找灵感,或在瑜伽馆放松减压。

2NF 常见问答

在没有复合键的数据库中能应用第二范式(2NF)吗?

可以!虽然 2NF 经常涉及复合键,但如果所有非主属性都完全依赖主键,单键表也同样可以满足 2NF 原则。

达到 2NF 是否能保证消除数据库中的所有冗余?

不能。2NF 消除了部分依赖,但不处理传递依赖。为此,您需要推进到第三范式(3NF)。

是否存在仅处于 1NF 而无需推进到 2NF 的情况?

有。在非常简单、数据冗余极少的系统或原型中,1NF 可能已足够。但除非有非常具体且合理的理由,我一般不建议停留在 1NF。

2NF 与第三范式(3NF)有什么区别?

2NF 消除部分依赖,确保属性依赖于整个键。3NF 更进一步,移除传递依赖,确保属性直接依赖主键,而非其他非键属性。

如何检查我现有的数据库是否已达到 2NF?

您可以通过审查所有带有复合键的表,并验证所有非主属性是否依赖于整个复合键而非其部分,来进行检查。

主题