数据库册 · 配套教学 · 按《数据库系统概论》第 6 版核心章节

数据库理论与设计教学

SQL 之外的核心内容,共六课:关系模型与关系代数、安全性与完整性、范式与模式分解、E-R 设计与转换、事务与并发控制、恢复技术。 每课结构:概念讲解 → 示例 → 要点 → 课堂练习(可展开参考答案)。

6 课 · 含练习 关系代数 范式 / E-R 事务 / 恢复

第 1 课 关系模型与关系代数

对应教材第 2 章。SQL 的理论基础。

关系就是一张二维表,但有三条规范化要求:列同质、列可交换、行不重复。 关系代数用一组运算描述查询,是 SQL 的数学基础。 五种基本运算是并、差、笛卡尔积、选择、投影,其余(交、连接、除)都可由它们导出。

-- 关系代数符号与含义
σ(选择):按条件挑行      π(投影):挑指定的列
∪ 并   − 差   ∩ 交   × 笛卡尔积   ⋈ 连接   ÷ 除

-- 例:查询选修了 2 号课程的学生的姓名
π Sname (σ Cno='2' (SC ⋈ Student))

-- 例:查询选修了全部课程的学生学号(除运算)
π Sno,Cno (SC) ÷ π Cno (Course)

-- 对应的 SQL 写法(EXISTS 表达形式)
SELECT Sno FROM Student
WHERE NOT EXISTS (
  SELECT * FROM Course WHERE NOT EXISTS (
    SELECT * FROM SC WHERE SC.Sno = Student.Sno AND SC.Cno = Course.Cno));
要点
  • 并、差、交要求两个关系的属性个数相同且类型相容;笛卡尔积无此要求。
  • 自然连接按同名属性等值连接并去掉重复列;等值连接保留重复列。
  • 除运算用于"全部 / 所有"类查询,对应 SQL 中的双层 NOT EXISTS。
  • 三类完整性:实体(主码非空不重)、参照(外码取值受限)、用户定义。
课堂练习(4 题)
  1. 用关系代数表示:查询计算机系(CS)全体学生的学号与姓名。 答:π Sno,Sname (σ Sdept='CS' (Student))
  2. 用关系代数表示:查询至少选修了一门课的学生姓名。 答:π Sname (Student ⋈ π Sno (SC))
  3. 自然连接与等值连接的结果有何差别? 答:自然连接在等值连接的基础上去掉重复的属性列(同名属性只保留一份)。
  4. 关系代数的基本运算为什么不包含交、连接、除? 答:因为它们可由五种基本运算导出(如 A∩B = A−(A−B)),引入只是为了表达方便。

第 2 课 安全性与完整性

对应教材第 4、5 章。一个防"非法的人",一个防"不合法的数据"。

安全性关注防止非法用户与非法操作,手段包括身份鉴别、存取控制、视图、审计、加密; 完整性关注数据本身是否正确、有效、相容,手段是各类约束与触发器。 二者目标不同:即使一个用户完全合法,也可能输入违反语义的数据——这正是完整性要管的。

-- 自主存取控制
GRANT SELECT ON TABLE Student TO U1 WITH GRANT OPTION;   -- 可再授权
GRANT UPDATE(Sage) ON TABLE Student TO U2;               -- 列级权限
REVOKE UPDATE(Sage) ON TABLE Student FROM U2;
CREATE ROLE R1;  GRANT SELECT ON TABLE Student TO R1;  GRANT R1 TO 王平;

-- 完整性约束
CREATE TABLE SC (
  Sno   CHAR(9)  NOT NULL,
  Cno   CHAR(4)  NOT NULL,
  Grade SMALLINT CHECK (Grade BETWEEN 0 AND 100),   -- 用户定义完整性
  PRIMARY KEY (Sno, Cno),                            -- 实体完整性
  FOREIGN KEY (Sno) REFERENCES Student(Sno)          -- 参照完整性
    ON DELETE CASCADE ON UPDATE NO ACTION
);

-- 命名约束后便于修改
ALTER TABLE SC DROP CONSTRAINT C1;
要点
  • 自主存取控制(DAC)按权限授权;强制存取控制(MAC)按密级标记强制约束。
  • 参照完整性违约处理:NO ACTION(拒绝)、CASCADE(级联)、SET NULL(该列须可空)。
  • 审计是事后手段,加密是事前手段,视图可用来隐藏数据实现授权。
课堂练习(4 题)
  1. 简述数据库安全性与完整性的区别。 答:安全性防止非法用户与非法操作,保护数据不被泄露或破坏;完整性保证数据本身正确、有效、相容,防止不合语义的数据进入数据库。
  2. U1 把权限转授给了 U2,收回 U1 权限后 U2 仍有权限,原因是什么? 答:REVOKE 未写 CASCADE,不会级联收回 U1 转授出去的权限。
  3. 删除 Student 中某元组时被拒绝,可能的原因是什么? 答:SC 中存在引用该学生的外码,且外码的删除违约策略为 NO ACTION(默认),因此拒绝删除。
  4. 哪种违约处理要求外码列允许为空? 答:SET NULL(置空值)策略,因为需要把外码列写成 NULL。

第 3 课 范式与模式分解

对应教材第 6 章。判断"表设计得好不好"的标准。

设计不好的关系模式会带来冗余与三类异常(插入、删除、更新)。 规范化通过分解关系模式逐步消除不合适的函数依赖: 1NF(属性不可再分)→ 2NF(消除非主属性对码的部分依赖)→ 3NF(消除传递依赖)→ BCNF(所有决定因素都含码)→ 4NF(消除多值依赖)。 求候选码的标准方法是属性闭包。

-- 例:关系模式 SLC(Sno, Sdept, Sloc, Cno, Grade),语义为一个学生只在一个系
-- 函数依赖:Sno → Sdept,Sdept → Sloc,(Sno,Cno) → Grade
-- 码:(Sno, Cno)
-- 问题:Sdept 与 Sloc 只依赖于 Sno(部分依赖)→ 不是 2NF,存在冗余与更新异常
-- 分解:SL(Sno, Sdept, Sloc) 与 SC(Sno, Cno, Grade)
--       SL 中 Sno → Sdept → Sloc 是传递依赖 → 再分解为 SD(Sno, Sdept) 与 DL(Sdept, Sloc)

-- 最后得到三个 3NF 关系:SD(Sno,Sdept)、DL(Sdept,Sloc)、SC(Sno,Cno,Grade)
要点
  • 求候选码:先找出只在依赖左部出现的属性(必含于任何码),再求闭包验证。
  • 判断范式要逐层检查:先 2NF(是否存在部分依赖),再 3NF(是否存在传递依赖),再 BCNF。
  • BCNF ⊂ 3NF:满足 BCNF 一定满足 3NF,反之不成立。
  • 模式分解的两个标准:无损连接性与保持函数依赖,二者有时不可兼得。
课堂练习(4 题)
  1. 关系模式 R(A,B,C),F = {A→B, B→C},求候选码并判断最高范式。 答:A 的闭包为 {A,B,C},候选码为 A。A→B→C 是传递依赖,非主属性 C 传递依赖于码 A,故最高只到 2NF,不属于 3NF。
  2. 什么叫无损连接分解? 答:分解后的若干关系做自然连接能够完全还原原关系(不多不少),则称该分解具有无损连接性。
  3. 3NF 与 BCNF 的区别是什么? 答:3NF 允许主属性对码的部分或传递依赖,BCNF 要求每一个决定因素都必须包含码,因此 BCNF 更严格。
  4. 分解时无法同时做到无损连接与保持函数依赖,应如何选择? 答:通常优先保证无损连接性(否则会丢失或增生信息),保持依赖可退而求其次,必要时用触发器等机制在应用层维护。

第 4 课 E-R 设计与关系模式转换

对应教材第 7 章。从需求到表结构的完整过程。

数据库设计分六个阶段:需求分析 → 概念结构设计(E-R 图)→ 逻辑结构设计(转成关系模式)→ 物理结构设计 → 实施 → 运行维护。 其中最关键的是 E-R 图向关系模式的转换,转换规则按联系的基数(1:1、1:n、m:n)而不同。

-- 转换规则要点
-- ① 一个实体型 → 一个关系模式,实体的属性即关系的属性,实体的码即关系的码
-- ② 1:1 联系:可并入任意一端(在该端加另一端的码),也可单独建关系
-- ③ 1:n 联系:并入 n 端(在 n 端关系中加 1 端的码),若联系有属性则一并加入
-- ④ m:n 联系:必须单独建立一个关系,属性为两端实体的码 + 联系自身的属性,码为两端码的组合
-- ⑤ 三个及以上实体的多元联系:单独建关系,码为各实体码的组合

-- 例:学生与课程是 m:n 联系"选修",带属性"成绩"
-- Student(Sno, Sname, ...)      Course(Cno, Cname, ...)
-- SC(Sno, Cno, Grade)           主码 (Sno, Cno),两个外码分别参照 Student 与 Course
要点
  • 概念模型独立于具体 DBMS,逻辑结构设计才与数据模型(关系/层次/网状)相关。
  • E-R 图的三要素:实体(矩形)、属性(椭圆)、联系(菱形),联系要标注基数。
  • 合并 E-R 图时要解决三类冲突:属性冲突、命名冲突、结构冲突。
  • 逻辑设计阶段还要做关系模式优化(通常以 3NF 为目标)。
课堂练习(4 题)
  1. 为什么 m:n 联系必须单独建立关系模式? 答:一个实体可以对应多个另一端的实体,无法用单一属性表示,必须用独立的关系记录每一对关联,并把两端主码组合作为该关系的码。
  2. 1:n 联系如何转换?举例说明。 答:并入 n 端。例如"系—学生"为 1:n,可在 Student 中加属性 Sdept(系号)作为外码,联系自身的属性也一并加入。
  3. 需求分析阶段的主要产物是什么? 答:数据流图与数据字典(数据项、数据结构、数据流、数据存储、处理过程),以及需求说明书。
  4. 合并分 E-R 图时要消除哪些冲突? 答:属性冲突(类型/取值范围不一致)、命名冲突(同名异义、异名同义)、结构冲突(同一对象在不同应用中抽象不同)。

第 5 课 事务与并发控制

对应教材第 12 章(事务概念见第 11 章)。

多个事务并发执行会产生三类数据不一致:丢失修改、不可重复读、读脏数据。 并发控制的目标是让并发调度的结果等价于某种串行调度(可串行化)。 最常用的机制是封锁:X 锁(写锁、排它)、S 锁(读锁、共享),配合不同级别的封锁协议解决问题。

-- 事务
BEGIN TRANSACTION;
  SELECT ...;  UPDATE ...;
COMMIT;              -- 提交;出错则 ROLLBACK 回滚

-- 封锁与协议
-- 一级封锁协议:修改前加 X 锁直到事务结束   → 防止丢失修改
-- 二级封锁协议:一级 + 读取前加 S 锁读完即放 → 防止读脏数据
-- 三级封锁协议:一级 + 读取前加 S 锁直到结束 → 防止不可重复读

-- 两段锁协议:加锁阶段与解锁阶段严格分开 → 保证并发调度可串行化
-- 多粒度封锁:意向锁 IS / IX / SIX 提高加锁检查效率
要点
  • 事务 ACID:原子性、一致性、隔离性、持久性。
  • 可串行化是并发调度正确性的准则;冲突可串行化是其充分条件(判定用优先图是否有环)。
  • 两段锁协议保证可串行化,但可能产生死锁;一次封锁法不会死锁但并发度低。
  • 活锁用先来先服务避免;死锁用超时法或等待图法检测、撤销事务解除。
课堂练习(4 题)
  1. 什么是丢失修改?举例说明。 答:两个事务同时读同一数据并各自修改,后提交的覆盖了先提交的结果,导致先前的修改丢失。例如 T1 与 T2 同时读余额 100,分别减 10 与减 20,最终结果取决于谁最后写入,其中一次修改被覆盖。
  2. 两段锁协议与一次封锁法的区别? 答:两段锁把加锁与解锁分为两个阶段,允许逐步加锁,能保证可串行化但可能死锁;一次封锁法要求一次申请全部锁,不会死锁但降低并发度。
  3. 如何判断一个调度是冲突可串行化的? 答:构造优先图(冲突操作按先后连边),若图中无环,则为冲突可串行化调度;有环则不是。
  4. 事务的持久性由什么机制保证? 答:由恢复机制保证——通过日志文件与"先写日志"原则,已提交事务的修改在系统故障后仍可重做(REDO)。

第 6 课 恢复技术

对应教材第 11 章。出故障后如何把数据库恢复到正确状态。

恢复的两大支柱是数据转储(备份副本)与日志文件(记录每次更新)。 核心原则是先写日志:必须先把日志记录写到稳定存储,再写数据库,否则故障后无法判断该重做还是撤销。 恢复时,对未完成事务做 UNDO(撤销),对已提交但未落盘的事务做 REDO(重做)。

-- 日志记录的典型内容
--  事务开始标记:<Ti BEGIN>
--  更新记录:<Ti, 数据对象, 旧值, 新值>
--  提交标记:<Ti COMMIT>

-- 恢复策略
-- 事务故障:反向扫描日志,对该事务的更新执行 UNDO,直到 BEGIN
-- 系统故障:正向扫描找已提交事务 → REDO;未完成事务 → UNDO
-- 介质故障:装入最近的后备副本 + 重做此后所有已提交事务

-- 检查点技术:定期写检查点记录,恢复时只需处理检查点之后的事务,缩短扫描范围
要点
  • 先写日志原则(WAL):先写日志再写数据库,是恢复正确性的前提。
  • UNDO 撤销未完成事务,REDO 重做已提交事务,方向不要搞反。
  • 检查点只是缩短扫描范围,不能替代日志;数据库镜像用于提高可用性。
  • 故障种类:事务内部故障、系统故障、介质故障、计算机病毒。
课堂练习(3 题)
  1. 为什么必须先写日志再写数据库? 答:若先写数据库后写日志,在两次写入之间发生故障,日志中没有该修改记录,恢复时既无法撤销也无法重做,数据库会处于不一致状态。
  2. 系统故障恢复时,哪些事务需要 REDO,哪些需要 UNDO? 答:日志中有 COMMIT 记录的事务需要 REDO(重做其修改),只有 BEGIN 没有 COMMIT 的事务需要 UNDO(撤销其修改)。
  3. 检查点的作用是什么? 答:周期性记录当前活跃事务与脏页信息并强制写盘,恢复时从最近的检查点开始处理,避免扫描整个日志,加快恢复速度。