数据键、函数依赖与规范化
各种键如何标识一条记录?
| 术语 | 精确定义 |
|---|---|
| 超键 | 足以唯一标识记录的属性集合,可以包含多余属性 |
| 候选键 | 不含多余属性的最小超键 |
| 主键 | 被选作主要标识的候选键 |
| 备用键 | 未被选为主键的其他候选键 |
| 复合键 | 由多个属性组合而成的键 |
| 外键 | 引用另一关系中受唯一性约束的键,也可自引用 |
| 代理键 | 系统生成、通常不承载业务含义的标识 |
- 原文修正: 非主键列不都叫备用键;“所有键的集合”也不是超键的定义;
函数依赖怎样暴露重复事实?
- 函数依赖: 若 X 的值相同就必然决定相同的 Y,记作
X → Y,表达的是业务约束而非偶然数据现象; - 部分依赖: 非主属性只依赖某个复合候选键的一部分,而不是整个键;
- 传递依赖: 通过中间属性间接决定另一属性,例如员工决定部门、部门决定部门电话;
- 原文修正: “主键决定其他属性”本身并不叫部分依赖,关键是只依赖复合键的真子集;
冗余数据为何产生插入、更新和删除异常?
- 插入异常: 想保存一种事实却被迫提供尚不存在的另一种事实,例如员工和团队强绑导致未分组员工无法录入;
- 更新异常: 同一事实重复多行,修改时漏掉一行就出现矛盾,例如同一个人的角色在多行不一致;
- 删除异常: 删除最后一条关联记录时连带丢失独立事实,例如删除团队记录同时丢掉成员资料;
- 判断条件: 异常取决于实际键与非空等约束,不能只凭某个表里出现重复名字就认定是同一个人;
范式如何约束依赖关系?
| 范式 | 核心要求 |
|---|---|
| 1NF | 属性值在所选模型中不可再拆为重复组,记录结构明确 |
| 2NF | 满足 1NF,非主属性完全依赖每个候选键 |
| 3NF | 每个非平凡依赖 X→A 中,X 是超键或 A 是主属性 |
| BCNF | 每个非平凡函数依赖的决定项都是超键 |
- 常见理解: 3NF 通常用于消除非键属性经由其他非键属性产生的传递依赖,正式定义还能处理多个候选键;
- BCNF: 比 3NF 更严格,原文也称 3.5NF,重点是决定项必须能唯一标识记录;
- 更高范式: 4NF、5NF、6NF 属于原文列出的延伸主题,本文不把未展开内容伪装成已覆盖知识;
- 收益: 减少冗余、强化参照完整性并让结构更清楚,代价是建模、联接与维护工作;
反规范化如何换取读性能?
- 反规范化: 为明确的查询路径有意保存派生或冗余数据,减少联接与跨节点取数;
- 适用条件: 已找到高成本读取,并能说明每份冗余数据由谁生成、何时更新及如何修复;
- 代价: 增加空间与写入成本,部分更新失败会造成不一致,读查询更简单不等于系统总维护更简单;
- 原则: 先理解正确的数据关系,再有意识加入冗余;它不是取消所有规范化规则;
如何把重复事实拆成明确的关系?
- 示例: 若员工所在部门决定部门电话,把部门电话移到以部门为键的表,员工只引用部门,更新电话就不必修改每个员工行;
- 连接要求: 分解后应能无损恢复需要的关系,不能为了去重把本来不同的事实错误合并;
- 实施检查: 确认外键、唯一性与非空要求表达真实业务规则,再用代表性查询检查联接成本;