【系统架构设计师】数据库系统 ⑥ ( 规范化理论 | 非规范化问题 | 函数依赖 | 部分函数依赖 | 传递函数依赖 | 候选键 | 求取 关系 的 候选键 )





一、非规范化问题




1、非规范化 问题简介


非规范化 的 关系模式 , 存在如下问题 :

  • 数据冗余 : 同一数据数据库的多个位置 重复存储 , 造成 存储空间的浪费 , 数据一致性维护成本增加 ;
    • 非规范化设计 : 数据表 未通过范式分解 , 导致 字段之间存在 不必要的 依赖关系 ;
    • 多字段组合存储 : 例如 将学生信息 和 课程信息 混合存储 , 导致学生姓名、学院等信息在每条课程记录中重复 ;
  • 更新异常 : 修改数据时 , 可能 因冗余导致部分数据未同步更新 , 引发数据不一致 , 导致 数据可信度降低 , 维护一致性 需要复杂的更新逻辑 ;
    • 冗余数据未集中管理 : 同一数据分布在多个记录或表中 ;
    • 依赖关系复杂 : 数据间的 逻辑依赖 未被合理约束 ;
  • 插入异常 : 无法插入某些必需数据 , 除非同时插入其他不相关数据 ; 导致 无法独立插入关键业务数据 , 需要设计临时占位数据 , 破坏数据完整性 ;
    • 主键依赖不合理 : 主键包含不必要字段 , 导致插入时 必须提供无效数据 ;
    • 数据耦合性高 : 实体信息与关联信息未分离 ;
  • 删除异常 : 删除数据时 , 意外丢失其他必要信息 ; 导致 关键数据意外丢失 , 需通过额外逻辑 保留必要数据 , 增加复杂度 ;
    • 数据耦合性高 : 不同实体的数据存储在同一表中 ;
    • 依赖关系未隔离 : 删除一个实体的数据 会连带删除其他实体数据 ;

2、非规范化 问题原因


非规范化 关系模式 原因总结 : 非规范化 核心问题 源于 数据依赖关系不合理 ;

  • 部分函数依赖 : 非主键字段 仅依赖主键的一部分 , 违反 2NF ;
  • 传递函数依赖 : 非主键字段 间接依赖主键 , 违反 3NF ;

3、非规范化 示例说明


下面的表格中 , 有 学号、姓名、系号、系名、系位置 属性 , 几乎将系统所需要的所有数据 , 放在了一个表格中进行处理 ;

在这里插入图片描述

上述表格 中 , 会出现一系列的 非规范化 问题 ;

  • 数据冗余 : 表格中 , 系名 和 系位置 属性 , 每个属性都是一个长字符串 , 占用了很多的存储空间 , 假如有 100 万条学生数据 相应的 数据冗余是很大的 , 浪费了大量的存储空间 ;
  • 更新异常 : 如果 系位置 发生了改变 , 那么就需要将 100 万个 学生信息实体 元组行 都需要进行修改 , 操作数据量大 , 容易出错 导致 漏掉某些元组的修改 ;
  • 插入异常 : 数据库表 中的 主键必须是 非空的 , 如果 新创建一个系 , 还没有招生 , 那么 新插入的系的 学号主键 就是空的 ;
  • 删除异常 : 有个系 被取消 , 不再招生 , 删除 某个系 , 删除过程会同时删除学生信息 ;

4、非规范化 解决方案


解决上述问题 , 就是 规范化 上述关系 , 通过分解表结构 , 消除冗余和异常 ;

  • 1NF : 确保 字段 原子性 ( 不可再分 ) ;
  • 2NF : 消除 非主键字段 对主键的 部分依赖 ;
  • 3NF : 消除 非主键字段间 的 传递依赖 ;
  • BCNF : 进一步 消除 主键字段间 的依赖 ;

上述示例 规范化后的表 :

学生表 ( 学号, 姓名, 系号 )
系表 ( 系号, 系名, 系位置 )




二、规范化理论 - 函数依赖




1、函数依赖 概念说明


函数依赖 概念 : R ( U , F ) 是 二元关系 , R 是实体 , U 是 属性集合 , F 是 依赖集合 ,

X 、 Y 是 属性集合 U 的 子集 ,

r 是 任意一个 关系 ,

如果 r 中 任意两个 元组 u 、 v , 只要有 u[X] = v[X] 就有 u[Y] = v[Y] ,

X 函数决定 Y , Y 函数依赖于 X , 可以记做 X -> Y ;

  • 决定因素 : " -> " 符号 左侧 的 X 是 决定因素 ;
  • 被决定因素 : " -> " 符号 右侧 的 Y 是 被决定因素 ;

2、函数依赖 示例说明


给定一个二元关系 :

学生 ( U , F )
U = {
    
    学号 , 姓名 , 年龄 , 班级编号}
F = {
    
    学号 -> 姓名 , 学号 -> 年龄 , 学号 -> 班级编号}

如 : X 是 {学号} , Y 是 {姓名} , 学号 -> 姓名 , 学号 函数决定 姓名 , 姓名 函数依赖于 学号 ;


X 属性存在 , 对应的 Y 属性自然而然的存在 , 如 : 给定一个学生的学号 , 肯定有一个对应的 学生的姓名 , 学生的年龄 , 学号 就可以 函数决定 姓名 和 年龄 , 姓名 和 年龄 函数依赖于 学号 ;


反过来说 Y 不能决定 X , 根据 年龄 是不能找到学生的学号的 , 一年级的学生 年龄 都是 6 岁 , 姓名 和 年龄 是无法唯一确定一个 学生 实体的 ;


3、部分函数依赖


在关系模式中 , 若 某个 非主属性(Non-Prime Attribute) 依赖于 候选键(Candidate Key)的 部分属性 , 而非 整个候选键 , 则称为 " 部分函数依赖 " ;

非主属性 仅依赖 候选键的部分属性 , 常见于 复合主键 ;


部分函数依赖 示例 : 下面的关系模式 R1 中 , 属性 AB 函数决定 属性 D , 属性 D 函数依赖 于 属性 AB ;

属性 A 和 B 不能 单独 决定 D , 必须组合在一起 才能 函数决定 D ;

在这里插入图片描述


在 查找 关系 R1 的 候选键 时 , 如果 想要 在 有向图 中遍历到 D , 必须将 A 和 B 属性一起放入到 集合 L 中 ;


属性 C 依赖于 候选键 { A , B } 中的 一部分属性 { A } , 不是依赖于 所有的 候选键 { A , B } , 这种依赖 称为 " 部分函数依赖 " ;


4、传递函数依赖


若 存在 属性集合 A -> B 且 B -> C,但 B 不决定 A , 则称 C 通过 B 传递依赖于 A ;

非主属性 通过 中间属性 间接依赖候选键 , 形成依赖链 ;


传递函数依赖 示例 : 下面的关系模式 R2 中 , 属性 A 函数决定 属性 B , 属性 B 函数决定 属性 C ;

属性 A 到 属性 C 就是 间接的 传递函数依赖 ;

在这里插入图片描述





三、候选键




1、候选键 概念简介


候选键多属性集合 , 唯一可以标识 元组行 , 且没有任何 冗余 ;

一个关系 可以有 多个 候选键 ;

任意选择一个 候选键 可以作为 关系的 主键 ;

主属性 与 非主属性 : 出现在 候选键 中的属性 称为 " 主属性 " , 其它属性 称为 " 非主属性 " ;

在这里插入图片描述


【系统架构设计师】数据库系统 ④ ( 关系模型 | 数据模型 三要素 | 数据模型 种类 | 关系模型 的 表示形式 | 关系模型相关概念 | 完整性约束 | 触发器 ) 博客中 对 候选码 、 主键 、 主属性 、 非主属性 、 外键 进行了简要说明 :

在这里插入图片描述


2、求取 关系 的 候选键


使用 " 图示法 " 查找 关系的 候选键 , 使用 " 有向图 " 的方式 分析 关系模式 的 函数依赖关系 ;

R ( U , F ) 是 关系模式 的表示方式 , U 是 属性集合 , F 是 依赖集合 ;

  • 属性集合 U 作为 有向图 的 节点 ;
  • 依赖集合 F 作为 有向图 的 有向边 ;

有向图 节点 的 入度 和 出度 : 箭头流出 是 出度 , 箭头流入 是 入度 ;

  • X、Y 是两个属性 , X 函数决定 Y , Y 函数依赖于 X , 记做 X -> Y ;
  • X 属性节点 的 出度为 1 , 入度为 0 ;
  • Y 属性节点 的 出度为 0 , 入度为 1 ;
  • 上述 依赖 的 有向边 方向是 X -> Y ;

候选键遍历 : 在 上述 " 有向图 " 中 , 找到 " 入度 为 0 " 的 属性节点 , 放在 " 遍历属性集合 " 中 , 以 该属性集合 中的属性节点 为起点 , 遍历 有向图 ,

  • 遍历多次 : 不需要一次遍历完 , 可遍历多次 ;
  • 间接遍历 : 不需要 完全 直接遍历 , 可以通过 多个节点传导遍历 , 间接遍历也可 ;

分析遍历结果 :

  • 如果 能 正常遍历 有向图 中的所有节点 , 则 该 " 遍历属性集合 " 就是 关系模式的 候选键 ;
  • 如果 不能 正常遍历 有向图 中的所有节点 , 则 该 " 遍历属性集合 " 就不是 关系模式的 候选键 ;
    • 此时 需要 尝试 将 " 既有入度 又有出度 " 的 " 中间结点 " 并入 到 " 遍历属性集合 " 中 , 继续 以 集合中的属性节点 为起点 , 遍历有向图 , 直到 能够 正常遍历 有向图 中的所有节点 ;




四、软考考点




1、求取候选码 1


给定关系 R ( A1 , A2 , A3 , A4 ) , 该关系上的 函数依赖为 F = { A1 -> A2 , A3 -> A2 , A2 -> A3 , A2 -> A4 } ,

将 属性 " A1 , A2 , A3 , A4 " 和 函数依赖 F , 绘制成 " 有向图 " , 可以得到下面的 有向图 ;

在这里插入图片描述


入度为 0 的 属性节点是 A1 , 将 A1 属性放入 " 遍历属性集合 " L 中 , L = { A1 } ;

以 A1 为起点 , 遍历 有向图 , 可以直接遍历到 A2 , 间接遍历到 A3 和 A4 , 可以完全遍历 整个 有向图 , 则 " 遍历属性集合 " L = { A1 } , 就是 该关系 R 的 " 候选键 " ;


{ A1 } 属性集合 是 R 的 候选键 ;

A1 属性 是 R 关系的 主属性 , A2 、A3 、A4 是 R 关系的 非主属性 ;


2、求取候选码 2


给定 关系模式 R ( U , F ) , 其中

  • 属性集合 U = { A , B , C , D , E , F , G , H , I , J } ;
  • 依赖集合 F = { ABD -> E , AB -> G , B -> F , C -> J , CJ -> I , G -> H } ;

求 上述 关系 R 的 候选键 ;


将 上述 属性集合 U 中的元素作为 有向图 的 节点 , 依赖集合 F 作为 有向图 的 有向边 , 绘制成的 有向图 如下图所示 :

在这里插入图片描述


找到 入度 为 0 的 属性节点 , 将其放入 集合 L 中 , L = { A , B , D , C } ;

以 L 集合 属性为起点 , 可以 遍历 所有 的 属性节点 ;


L = { A , B , D , C } 集合 , 可以作为 关系 R 的候选键 ;


3、求取候选码 3


给定 关系模式 R ( U , F ) , 其中

  • 属性集合 U = { A , B , C } ;
  • 依赖集合 F = { B -> C , B -> A , A -> BC } ;

求 上述 关系 R 的 候选键 ;


在这里插入图片描述


尝试 找到 入度 为 0 的 属性节点 , 将该属性节点放入集合 L , 发现没有 入度为 0 的 属性节点 ;

此时 L = { Φ } ;

查找入度为 1 的节点 , 放入 集合 L 中 ;

  • 将 A 节点放入集合 L 中 , L = { A } , 此时 以 L 集合 属性为起点 , 可以 遍历 所有 的 属性节点 ;
  • 将 B 节点放入集合 L 中 , L = { B } , 此时 以 L 集合 属性为起点 , 可以 遍历 所有 的 属性节点 ;
  • C 的 入度为 2 , 并且没有出度 , C 不能作为候选键 ;

上述关系 R 的候选键为 { A } 或者 { B } , 任意一个都可以作为 候选键 ;

注意 : { A , B } 不能作为候选键 , 因为 单独的 A 属性 或者 单独的 B 属性 都可以作为候选键 , 两个属性一起就出现了 冗余 ;

猜你喜欢

转载自blog.csdn.net/han1202012/article/details/146958115
今日推荐