当前位置: 首页 > news >正文

数据库范式(Normalization)

一个设计混乱的数据库就像一个杂乱的房间,用起来非常不方便:东西到处乱放(数据冗余),找件东西要翻遍所有角落(查询困难),扔掉一把旧椅子时,可能会把搭在上面的唯一一件外套也一起扔了(删除异常)。

数据库范式(Normalization) 就是一套“房间整理法则”,指导我们如何合理地组织数据表,以消除冗余、避免上述问题。2NF和3NF是其中最核心、最重要的两条法则。

初始状态:乱糟糟的第一范式 (1NF)

假设我们要设计一个系统来记录学生的选课成绩。最直接的想法可能是把所有信息都塞进一张大表里。这张表符合第一范式(1NF),因为每个单元格都只有一个值,并且没有完全重复的行。但你会发现,它问题重重。

选课成绩表 (符合1NF)

学号课程号学生姓名课程名称授课老师成绩
101CS101张三计算机导论王老师92
101MTH202张三高等数学李老师85
102CS101李四计算机导论王老师88
103PHY301王五量子力学赵老师95

我们先来分析这张表的“身份”信息:

  • 主码 (Primary Key): 要唯一确定一行数据,需要同时知道“哪个学生”和“哪门课”。因为一个学生可以选多门课,一门课也可以被多个学生选。所以,主码是 (学号, 课程号) 这样一个组合。
  • 主属性: 学号, 课程号
  • 非主属性: 学生姓名, 课程名称, 授课老师, 成绩

这张表虽然能用,但有严重的“副作用”(我们称之为“异常”):

  • 更新异常 (Update Anomaly): 如果学生“张三”改名叫“张大三”,你必须修改所有他出现的行。一旦漏掉一行,数据就不一致了。
  • 插入异常 (Insertion Anomaly): 你无法添加一个新生(比如学号104的“赵六”),除非他至少选了一门课。因为主码 (学号, 课程号) 要求 课程号 不能为空。
  • 删除异常 (Deletion Anomaly): 如果“王五”退掉了他唯一选的课(量子力学),那么他所在的整行数据都会被删除。我们不仅丢失了他的选课记录,连“王五”这个学生本身的信息也从数据库里消失了!

如何解决这些问题?答案就是遵循范式法则进行整理。


第一步整理:达到第二范式 (2NF)

2NF的法则

一个表在符合1NF的基础上,如果所有非主属性都“完全函数依赖”于主码,那么它就符合2NF。

  • “完全函数依赖”:听起来很学术,其实很简单。意思就是一个非主属性的值,必须由整个主码来唯一确定,而不是由主码的一部分就能确定。
  • 通俗版法则任何一个非主属性,都不能只依赖于组合主码的一部分。(这条规则只在主码是组合码时才有意义,就像我们这个例子)。
运用2NF法则整理

我们的主码是 (学号, 课程号)。我们来检查一下每个非主属性:

  • 成绩: 由什么决定?必须同时知道 学号课程号 才能确定一个唯一的成绩。所以,成绩 依赖于整个主码这很好,符合2NF。
  • 学生姓名: 由什么决定?只需要 学号 就能确定。学生的姓名和他选了什么课没关系。所以,学生姓名 只依赖于主码的一部分 (学号)。这很糟糕,违反了2NF。
  • 课程名称授课老师: 由什么决定?只需要 课程号 就能确定。这和哪个学生来选课也没关系。所以,这两个属性也只依赖于主码的一部分 (课程号)。这也很糟糕,违反了2NF。
解决方法:拆分!

解决办法就是“分家”。把那些只依赖于部分主码的信息,拆分出去成立自己的独立小家庭(新表)。

  1. 只依赖于 学号 的信息,放到新的 学生表 里。
  2. 只依赖于 课程号 的信息,放到新的 课程表 里。
  3. 依赖于 (学号, 课程号) 完整组合的信息,留在瘦身后的 选课表 里。

学生表 (Students)

学号 (主码)学生姓名
101张三
102李四
103王五

课程表 (Courses)

课程号 (主码)课程名称授课老师
CS101计算机导论王老师
MTH202高等数学李老师
PHY301量子力学赵老师

选课表 (Enrollment)

学号 (外码)课程号 (外码)成绩
101CS10192
101MTH20285
102CS10188
103PHY30195
(这张表的主码依然是 (学号, 课程号))

现在,我们所有的表都符合2NF了,之前提到的那些异常问题也随之解决!张三改名,只需改 学生表 一处。新生赵六可以直接添加到 学生表,不用非得选课。


第二步整理:达到第三范式 (3NF)

我们离完美还差一步。仔细看刚刚创建的 课程表,它里面还隐藏着一个问题。

3NF的法则

一个表在符合2NF的基础上,如果不存在“传递函数依赖”,那么它就符合3NF。

  • “传递函数依赖”:指的是一个非主属性,不直接依赖于主码,而是通过另一个非主属性间接地依赖于主码。形成了一个依赖链条:主码 -> 非主属性A -> 非主属性B
  • 通俗版法则任何一个非主属性,都不能依赖于其他非主属性。
运用3NF法则整理

为了让问题更明显,我们在 课程表 里加一列“老师所在院系”。

课程表 (符合2NF,但不符合3NF)

课程号 (主码)课程名称授课老师老师所在院系
CS101计算机导论王老师计算机系
MTH202高等数学李老师数学系
CS205数据结构王老师计算机系

我们来检查主码 课程号 和非主属性之间的依赖关系:

  • 课程名称 直接依赖于 课程号很好
  • 授课老师 直接依赖于 课程号(为简化,假设一门课只有一个老师)。很好
  • 老师所在院系: 老师的院系是由 课程号 决定的吗?不是! 它是由授课老师决定的。这样就形成了一个依赖链条:
    课程号 -> 授课老师 -> 老师所在院系
    这就是传递依赖,它违反了3NF。

这又会引发老问题!如果“王老师”从“计算机系”调到了“人工智能系”,你就必须修改他教的每一门课的记录,非常麻烦且容易出错。

解决方法:再次拆分!

我们把这个传递依赖链条也拆开,把老师的信息独立出去。

老师表 (Instructors)

授课老师 (主码)老师所在院系
王老师计算机系
李老师数学系
赵老师物理系

新的课程表 (Courses)

课程号 (主码)课程名称授课老师 (外码)
CS101计算机导论王老师
MTH202高等数学李老师
CS205数据结构王老师
PHY301量子力学赵老师

现在,如果王老师调动院系,我们只需在 老师表 中修改唯一的一条记录。至此,我们所有的表都达到了3NF,房间整理完毕!

最终总结

  • 1NF:入场券。 确保数据是“原子的”(每个单元格一个值)。
  • 2NF:消除部分依赖。 确保所有非主属性都依赖于整个组合主码,而不是它的一部分。(解决方法:把依赖于部分的属性拆出去)。
  • 3NF:消除传递依赖。 确保所有非主属性都依赖于主码,而不是依赖于其他非主属性。(解决方法:把间接依赖的属性拆出去)。

通过遵循这些法则,我们把一张庞大、混乱的表,拆分成了四个干净、清晰、健壮的小表:学生表老师表课程表选课表。这就是关系数据库设计的精髓所在。


文章转载自:

http://bS3SZX2E.xjbtb.cn
http://8iwP8tCM.xjbtb.cn
http://iPYvLWbq.xjbtb.cn
http://DxzMlhYs.xjbtb.cn
http://QDYoBA3l.xjbtb.cn
http://oxfx3rcA.xjbtb.cn
http://UQvSgQPD.xjbtb.cn
http://zHMfxrli.xjbtb.cn
http://smzsOiHY.xjbtb.cn
http://6OoeX2Wn.xjbtb.cn
http://NixJZBBR.xjbtb.cn
http://IKZRufIz.xjbtb.cn
http://5ZcEJFM4.xjbtb.cn
http://RDASfQtr.xjbtb.cn
http://3VZYc1dC.xjbtb.cn
http://VTtx8nHo.xjbtb.cn
http://7dqimbRZ.xjbtb.cn
http://Bp1oQnCQ.xjbtb.cn
http://h2ah3Wm4.xjbtb.cn
http://FzKhHS5T.xjbtb.cn
http://HVdT5I6o.xjbtb.cn
http://SYkWGT0O.xjbtb.cn
http://G536mJY7.xjbtb.cn
http://cNiVA0Ly.xjbtb.cn
http://wM0eIAeI.xjbtb.cn
http://MrAxMzZP.xjbtb.cn
http://2LXdIZRc.xjbtb.cn
http://rWmUczF6.xjbtb.cn
http://rCsnSE1x.xjbtb.cn
http://Gnpc6l7C.xjbtb.cn
http://www.dtcms.com/a/384070.html

相关文章:

  • 怎么永久删除.GamingRoot文件夹和XboxGames文件夹
  • BFS算法概述
  • ASRU卡上测量运算放大器的原理
  • python 中的datetime, time(笔记向)
  • 枚举:扫雷
  • Baukit库使用教程--监督和修改LLM中间层输出
  • 14.ImGui-DX11虚表hook(一)-认识虚表
  • 15.渗透-.Linux基础命令(六)-用户管理(group文件)
  • 数字赋能农业:多场景智慧农业解决方案与平台实践解析
  • App Router vs. Pages Router:我应该如何选择?
  • 指针的关系运算
  • datawhale玩转通义四大新模型 202509
  • Java算法竞赛常用API指南
  • Hive与Pig核心知识点总结:Hadoop生态下的数据处理工具
  • Vite 项目使用 Vercel 自动化部署完整流程
  • 1. 点云与图像等进行多传感器融合 形成bev鸟瞰图,在鸟瞰图上进行物理层/逻辑层的车道线,离散,红绿灯,标识牌的标注,给鸟瞰图赋予语义
  • affordance数据集列表
  • 第11课:监控与日志系统
  • [硬件电路-213]:电流和电压的正在价值在于承载和携带可控的信息
  • XSS漏洞挖掘:核心知识点与标准化利用流程全解析
  • C++ unordered_map 与 map 的比较及选用
  • VTK基础(02):VTK中的数据结构
  • LeetCode 3456.找出长度为K的特殊子字符串
  • C#使用OpenVinoSharp和PP-Mating进行人像抠图
  • 初始QML
  • 贪心算法python
  • 淘宝客app的API网关设计:认证授权与流量控制策略
  • python快速使用mcp服务
  • 绑定方法与非绑定方法
  • 北科大2025研究生英语超星慕课第一单元标准答案