数据冗余与规范化的本质[数据库原理]

我们把它想象成整理一个乱七八糟的杂物间的过程。我们的目标是把所有东西分门别类放好,让找东西、放东西、更新东西都变得轻松,并且避免重复占用空间。


第一部分:为什么要"规范化"?------ 解决"大杂烩"表的三大痛点

假设我们管理一个"学生选课"系统,最初设计了一张"万能表":

学号 学生姓名 院系 课程号 课程名 学分 成绩
1001 张三 计算机系 C001 数据库 4 90
1001 张三 计算机系 C002 数据结构 4 85
1002 李四 外语系 C003 英语文学 3 88

这张表看起来挺全,但用起来问题一大堆:

1. 数据冗余(重复存储,浪费空间)

  • 问题:张三选了2门课,他的"姓名"和"院系"就存了2次。如果他有10门课,就存10次。如果"计算机系"有500个学生,这个院系名就被重复存了成百上千次。
  • 后果:数据库变得臃肿,浪费存储空间。

2. 更新异常(改一处,动全身,容易出错)

  • 修改异常 :如果"计算机系"改名为"智能计算学院",你需要找到表中所有院系是"计算机系"的行,一行一行去改。只要有1行漏了,数据就矛盾了。
  • 插入异常:想新增一门新课"C004,人工智能,3学分",但目前还没有任何学生选它。由于"学号"是主键(不能为空),你竟然无法把这门新课的信息存入系统!
  • 删除异常:学生李四(1002)毕业了,我们删除他唯一的选课记录(C003)。糟糕!连"英语文学"这门课程本身的信息(课程名、学分)也从系统中永远消失了,因为课程信息只存在这条记录里。

规范化,就是为了解决以上所有这些问题。


第二部分:规范化的核心武器 ------ "函数依赖"

要整理房间,得先知道东西之间的归属关系。在数据库里,这个关系叫 "函数依赖"

通俗理解 :如果知道了A的值,就能唯一确定 B的值,那么就说 "B函数依赖于A" ,记作 A → B

  • 例子1学号 → 学生姓名。知道学号1001,一定能查到他是张三。
  • 例子2课程号 → 课程名。知道课程号C001,一定能查到它是"数据库"。
  • 例子3(学号, 课程号) → 成绩。必须同时知道是谁(学号)和哪门课(课程号),才能确定他的成绩。

依赖关系是进行"分类整理"的指导手册。


第三部分:规范化步骤详解(从1NF到3NF)

这就像整理房间的递进标准,一级比一级整洁。

第一范式:保证每件东西都是"最小单元"

  • 要求 :表中的每个格子(属性)必须是不可再分的基本数据项。不能把多个信息塞在一个格子里。
  • 违反例子:表中有一列叫"联系方式",里面填着"电话:123456,邮箱:abc@xx.com"。这就不是原子项。
  • 如何满足:拆成两列:"电话"和"邮箱"。
  • 目标:消灭"表中套表"。

第二范式:解决"部分依赖" ------ 把属于个人的东西归到个人档案里

  • 前提:已满足1NF。

  • 要求 :表中的所有非关键信息 ,必须完全依赖于整个主键(不能只依赖主键的一部分)。

  • 分析我们的"万能表"

    • 主键 :是 (学号, 课程号)。因为需要这两者才能唯一确定一个成绩。
    • 问题 :"学生姓名"和"院系"只依赖于主键中的 学号(知道学号就知道姓名和院系),而不依赖于 课程号。这就是部分依赖
    • 后果:导致张三的姓名和院系重复存储多次(数据冗余)。
  • 如何满足(分解)

    1. 创建"学生档案"表 :存放只依赖于学号的信息。

      学号 学生姓名 院系
      1001 张三 计算机系
      1002 李四 外语系
    2. 创建"课程档案"表 :存放只依赖于课程号的信息。

      课程号 课程名 学分
      C001 数据库 4
      C002 数据结构 4
      C003 英语文学 3
    3. 保留核心的"选课记录"表 :存放同时依赖于学号课程号的信息(成绩)。

      学号 课程号 成绩
      1001 C001 90
      1001 C002 85
      1002 C003 88
  • 效果:张三的姓名和院系只存了一次!"数据库"课程的信息也只存了一次!冗余大大减少。

第三范式:解决"传递依赖" ------ 把公共信息单独建册

  • 前提:已满足2NF。

  • 要求 :表中的非关键信息之间不能有依赖关系。即,不能出现 A → B → C 这种"传递链"。

  • 假设"学生档案"表增加了"院长"列

    学号 学生姓名 院系 院长
    1001 张三 计算机系 王院长
    • 分析 :这里存在 学号 → 院系院系 → 院长。所以"院长"信息是通过"院系"传递依赖于"学号"的。
    • 问题:如果计算机系换院长了,需要修改所有计算机系学生的记录(又是更新异常和冗余)。
  • 如何满足(再次分解)

    1. 创建"院系信息"表 :存放院系和其院长的对应关系。

      院系 院长
      计算机系 王院长
      外语系 李院长
    2. 简化"学生档案"表 :只保留对学号的直接依赖。

      学号 学生姓名 院系
      1001 张三 计算机系
      1002 李四 外语系
  • 效果:院长信息只存一次,修改时只需动一处。结构更清晰。


第四部分:规范化的好处与代价(平衡的艺术)

规范化后的好处(我们达到了目的):

  • 空间利用率高:数据冗余极低。
  • 维护简单:增删改操作通常只影响一张小表,准确高效。
  • 数据一致性强:相同信息只存一份,没有矛盾。

过度规范化的代价(新问题):

  • 表太多了:原来一张"万能表",现在可能拆成5-6张表。
  • 查询变慢 :想查"张三在计算机系王院长门下,数据库课考了多少分?",需要把学生表院系表选课表课程表这四张表连接起来,查询语句复杂,执行速度可能变慢。

因此,在实际中(特别是大数据、高并发场景):

  • 操作型系统 (如银行交易、订单录入):强调数据准确和写入效率,规范化程度要高(通常到3NF或BCNF)。
  • 分析型系统 (如报表、数据仓库):强调快速查询和读取,允许适度反规范化。比如,在"选课记录"表里直接冗余存储"学生姓名"和"课程名",虽然违反了范式,但查询时不用连表,速度飞快。

总结一下

关系规范化理论 ,本质上是一套 "拆表"的黄金法则

  1. 动机:看不下去"大杂烩"表的冗余和混乱。
  2. 方法:用"函数依赖"分析数据关系,像整理房间一样,把东西分门别类。
  3. 过程
    • 1NF:保证每个物品是独立的。
    • 2NF:把属于个人档案的东西单独放。
    • 3NF:把公共资料(如院系手册)再单独放。
  4. 目标 :达到结构清晰、易于维护的状态。
  5. 权衡:在"结构优雅"和"查询速度"之间,根据实际业务需求做平衡。
相关推荐
码农老李3 小时前
openEuler2403服务器版 原生官方镜像和飞腾定制镜像
开发语言·php
_ku_ku_3 小时前
数据库系统原理 · SQL 数据定义、更新及数据库编程 · 自学总结
数据库·oracle
Mortalbreeze4 小时前
深度理解文件系统 ---- 从磁盘存储到内核存储
大数据·linux·数据库
charlie1145141914 小时前
现代Qt开发教程(新手篇)2.3——QImage、QPixmap、QIcon 图像处理基础
开发语言·图像处理·qt
范范@4 小时前
python基础-函数
开发语言·python
2301_803934614 小时前
MySQL 字段类型选择规范指南
jvm·数据库·python
特种加菲猫4 小时前
从零开始手撕AVL树:详解插入、平衡因子更新与四种旋转
开发语言·c++
oddsand14 小时前
Redis网络模型
java·数据库·redis
皮卡祺q5 小时前
【redies0-导论】分布式系统的演进-引进redis原因
java·数据库·redis