期末复习最怕的不是知识点多,而是不知道老师想考什么。数据库系统这门课在西电计科的课程体系里属于那种“看着门槛不高、考起来全是细节”的类型——PPT 上画满了 E-R 图,课本里塞满了关系代数和范式判定,SQL 又能从单表查询一路考到三层嵌套和触发器,最后还给你来一道并发调度的可串行化判断。我当年复习的时候走了不少弯路,后来把整门课拆成“计算题、设计题、说理题、SQL 题”四个板块逐一攻破,效率高了很多。这篇笔记就把我整理过的核心考点、做题套路和踩坑经验全部摊开讲,适合正在备考数据库系统期末、尤其是手拿王珊《数据库系统概论》的同学参考。
1. 期末死磕之前,先建立整门课的知识框架
数据库系统这门课最大的特点是概念多、层次多、前后关联强。如果你一上来就背范式的定义,大概率背完就忘。我的建议是:先花一个小时把整门课的地图建起来,后面每个知识点都能挂到这张地图上,复习才会越往后越轻松。
1.1 课程主线:从数据到数据库,再到数据库管理系统
数据库系统研究的是如何把现实世界的数据用计算机高效、安全、可靠地管理起来。整门课可以沿着这样一条主线理解:
- 数据描述:现实世界 → 概念世界(E-R 模型)→ 机器世界(关系模型)
- 数据操作:SQL 查询、更新、视图、触发器
- 数据约束:完整性(实体、参照、用户定义)与安全性(用户认证、授权)
- 数据优化:函数依赖、范式分解、查询优化
- 数据保障:事务、故障恢复、并发控制
考试中所有题目基本都能归入这五类。你如果能在草稿纸上把这条主线默写出来,说明你对课程的整体把握已经没有问题了。
1.2 各章节在考试中的“地位”分布
根据我对历年期末试题的观察(不同年份略有浮动),各知识点的出题权重大概如下:
| 知识模块 | 典型题型 | 大致占比 | 复习优先级 |
|---|---|---|---|
| 关系模型与关系代数 | 计算题、小题 | 10% ~ 15% | 高 |
| SQL 语言 | 编程题(必考) | 20% ~ 25% | 极高 |
| 完整性/安全性/触发器 | 简答、SQL 编程 | 10% ~ 15% | 中高 |
| 函数依赖与范式 | 判断+分解大题 | 15% ~ 20% | 高 |
| 数据库设计(E-R 图) | 设计大题 | 10% ~ 15% | 高 |
| 事务/恢复/并发控制 | 简答+调度判断 | 15% ~ 20% | 中高 |
这张表不是让你去押题,而是帮你安排复习顺序。SQL 和范式这两块分值最大且最容易通过做题提分,建议放在精力最旺盛的时候集中刷;概念类题目适合放在碎片时间反复记。
2. 关系模型与关系代数:别只会背 σ 和 π,把除运算和连接搞明白
关系代数不是期末考试的绝对主角,但它是学习 SQL 的理论基础,很多学校喜欢在填空、选择和简答题里穿插几个小题。更重要的是,理解关系代数的运算逻辑之后,写复杂 SQL 的时候思路会清晰很多。
2.1 三个基本要素:关系、元组、属性
关系模型用“二维表”来表示数据,一张表就是一个关系。这里面有几个容易混淆的概念:
- 关系模式(Relation Schema):描述表的结构,如 Student(Sno, Sname, Ssex, Sage)
- 关系实例(Relation Instance):某时刻表中的具体数据,即元组的集合
- 候选码(Candidate Key):能唯一标识元组的最小属性组
- 主码(Primary Key):被选中的候选码
- 外码(Foreign Key):另一张表的主码,用来建立两表之间的关联
考试里常考的一个坑是:候选码可能有多个,主码只能有一个;主码的取值不能为空,外码可以为空。这个在判断关系完整性时特别重要。
2.2 选择、投影、连接的运算套路
关系代数的运算分为传统的集合运算(并、差、交、笛卡尔积)和专门的关系运算(选择、投影、连接、除)。
- 选择 σ:从行方向筛选,选出满足条件的元组。σSsex='男'(Student)
- 投影 π:从列方向筛选,选出某些属性列。πSno,Sname(Student)
- 自然连接 ⋈:等值连接后去掉重复属性列
做题时最容易出错的是自然连接和等值连接的区别。自然连接要求比较的字段必须同名,且结果中只保留一份该字段;等值连接可以比较不同名但值相等的字段,结果中两个字段都会保留。
2.3 除运算:理解它,嵌套查询更清楚
除运算(R ÷ S)是很多人的噩梦。它用一句话解释就是:在 R 中找到那些“与 S 中每一个元组都能匹配”的属性组。
举个例子:假设有选课关系 SC(学号, 课程号),有课程关系 C(课程号),那么 SC ÷ C 的结果就是选了全部课程的学生学号。判断结果是哪个属性,要看 R 中除去 S 中属性后还剩什么。SC ÷ C 的结果只有“学号”。
除运算的判别步骤(考场速算法):
- 确定结果属性:R 的属性集合减去 S 的属性集合
- 对 R 按剩余属性分组
- 找出那些“包含了 S 中所有属性组合”的组
除运算不常单独出大题,但在“查询选修了全部课程的学生姓名”“查询至少选修了学生 2 所选全部课程的学生学号”这类 SQL 题里,用 NOT EXISTS 双重否定来做,其实数学本质就是除运算。你把这个想通了,嵌套查询会顺很多。
2.4 关系代数题目考场技巧
- 先画表结构,把关系模式和已知数据写清楚
- 括号要先算:运算顺序和算术一样,括号优先级最高
- 注意属性名前加关系名:比如 σSC.Sno=Student.Sno(...),避免同名属性混淆
- 除运算的结果不要想当然,按“属性差 + 分组匹配”来推导
我复习的时候,把课后习题里的关系代数题全部手写了一遍,每次写完之后对照标准答案,发现错误大多集中在连接条件漏写、投影属性多列少写两个地方。这两个坑,考场上一定要留心。
3. SQL 编程题:从单表查询到嵌套 EXISTS 的得分要点
SQL 是数据库系统期末的“半壁江山”。每年的编程大题必有一两道,通常覆盖单表查询、多表连接、分组聚和、嵌套查询、视图和更新操作。这一部分没有别的捷径,就是多写、多练、多对比不同写法。
3.1 单表查询:SELECT 的执行顺序比你想的重要
很多同学写 SQL 是“凭感觉”,对着结果猜语句。但考试是没有运行环境的,你必须明确 SELECT 语句的完整执行顺序,才能保证逻辑严密:
- FROM:确定数据来源表
- WHERE:对行进行筛选
- GROUP BY:按列分组
- HAVING:对分组后的结果筛选
- SELECT:投影目标列
- ORDER BY:排序
- LIMIT:取前若干行(部分教材不讲,但很实用)
这解释了为什么 WHERE 中不能使用聚合函数而 HAVING 中可以,因为 WHERE 在 GROUP BY 之前执行,此时分组还不存在;HAVING 在 GROUP BY 之后执行,自然可以使用 COUNT、AVG 这类聚合函数。
一个典型的丢分点:
-- 查询平均成绩大于80分的学生学号 -- 错误写法: SELECT Sno FROM SC WHERE AVG(Grade) > 80; -- 正确写法: SELECT Sno FROM SC GROUP BY Sno HAVING AVG(Grade) > 80;3.2 多表连接:内连接、外连接到底怎么选
多表查询一般用 JOIN 或 WHERE 等值连接。考试中常见的判断点是:查询结果是否需要保留未匹配的元组。
- 内连接 INNER JOIN:只保留两边都匹配上的行
- 左外连接 LEFT JOIN:保留左表全部行,右表无匹配则补 NULL
- 右外连接 RIGHT JOIN:与左外连接相反
- 全外连接 FULL JOIN:两边都保留(部分数据库不支持)
比如要“查询每个学生的选课情况,包括没选课的学生”,那就必须用左外连接,以 Student 表为左表。如果题目说“查询有选课记录的学生”,才用内连接。
3.3 嵌套查询与 EXISTS 双重否定
嵌套查询的高频考点是“查询选修了全部课程的学生姓名”和“查询至少选修了学生 2 所选全部课程的学生学号”。这类题目的通用解法是双重 NOT EXISTS:
-- 查询选修了全部课程的学生姓名 SELECT Sname FROM Student WHERE NOT EXISTS ( SELECT 1 FROM Course WHERE NOT EXISTS ( SELECT 1 FROM SC WHERE SC.Sno = Student.Sno AND SC.Cno = Course.Cno ) );顺着读:不存在“某门课,这个学生没选”。等价于:这个学生选了所有课。这道题考的频率极高,建议你先把这段代码背到默写无误,再去理解逻辑。
我见过不少同学在这里卡住,原因是试图用COUNT(Cno) = (SELECT COUNT(*) FROM Course)来写。这种写法在概念上没问题,但在处理重复选课记录、NULL 值以及某些数据库的兼容性时容易翻车。考试时优先用 EXISTS 写法,稳妥。
3.4 视图、更新与触发器:三个容易被忽略的得分点
视图(VIEW)考试中常考两类:一是“创建视图”的 SQL 语句;二是“对视图的更新能否成功”。后者主要考察视图的可更新性:如果视图定义中包含分组、聚合、DISTINCT、多表连接等,视图通常不可更新。对这类视图做 INSERT、UPDATE 或 DELETE 会报错或不确定。
触发器(TRIGGER)是完整性和安全性章节的延伸考察点。创建触发器的基本框架:
CREATE TRIGGER trigger_name AFTER INSERT ON SC FOR EACH ROW BEGIN UPDATE Student SET TotalCredits = TotalCredits + NEW.Credit WHERE Student.Sno = NEW.Sno; END;需要记住的点:
- BEFORE 和 AFTER:指定触发时机
- FOR EACH ROW:行级触发器,每行触发一次
- NEW / OLD:分别表示新插入/更新后的行,和更新前/删除的行
- 触发器中不能对同一张表进行递归操作,防止无限触发
写触发器题时,先把“触发时机 + 触发事件 + 触发动作”三要素写清楚,再动手写代码,这样不容易漏条件。
4. 函数依赖与范式:判断“第几范式”和模式分解的完整操作流
范式这块是很多人期末翻车最惨的区域。原因在于它既有抽象概念,又有算法流程。但只要解题步骤固定化、套路化,拿分并不难。我总结了一套“三步判定法”和一套“无损分解法”,分享给大家。
4.1 三步判定“第几范式”
拿到一个关系模式和函数依赖集,不要靠直觉,按下面的步骤走:
求候选码:从函数依赖中找出能决定所有属性的最小属性组。常用 LRN 法——把属性分成四类:
- L 类:只在依赖左边出现
- R 类:只在依赖右边出现
- LR 类:两边都出现
- N 类:两边都没出现
候选码必包含全部 L 类和 N 类属性,再看能否由它们推出 R 类和 LR 类属性,决定是否扩展。
检查是否存在非主属性对候选码的局部函数依赖:如果有,则不属于 2NF
检查是否存在非主属性对候选码的传递函数依赖:如果有,则不属于 3NF
检查每个决定因素是否都是候选码:如果不是,则不属于 BCNF
以经典例子说明:关系模式 SLC(Sno, Sdept, Sloc, Cno, Grade),函数依赖集 F = {Sno → Sdept, Sdept → Sloc, (Sno, Cno) → Grade}。
- 候选码是 (Sno, Cno)
- 非主属性:Sdept、Sloc、Grade
- Sno → Sdept,而 Sno 是候选码 (Sno, Cno) 的一部分,所以存在部分函数依赖
- 结论:SLC 属于 1NF,但不属于 2NF
这么一步步推,比盯着关系表发呆靠谱得多。
4.2 模式分解:无损连接与保持函数依赖
范式不达标就要分,但分解不是乱分,必须保证两个性质:无损连接和(最好)保持函数依赖。
无损连接的判断可以用表格法(Chase 算法)。考试中更常考的是“给出一个分解,判断是否无损”,此时用表格法最稳。
表格法简版步骤:
- 建一张表:列为全部属性,行为每个分解后的关系模式
- 初始填 a 或 b:如果该属性属于该关系模式,填 a1、a2…,否则填 b11、b12…
- 对每一个函数依赖 X → Y,找 X 列取值相同的行,将对应 Y 列的符号改成相同(若其中一个是 a 则都改成 a)
- 循环直到不再变化
- 如果某一行全为 a,则是无损连接分解
很多同学在这个步骤上画错初始表格,导致后面全盘崩溃。我的建议是每一步都用铅笔标记改动来源,复查时特别方便。
关于保持函数依赖的判定:把分解后每个关系模式的函数依赖集取并集,如果能推导出原函数依赖集里的每一个依赖,就是保持函数依赖。
4.3 从 1NF 到 BCNF 的规范化路径
期末考试喜欢考“将该关系模式规范化为 3NF/BCNF”。这个题的套路是:
- 先求候选码
- 找出违反范式要求的函数依赖(部分依赖或传递依赖)
- 把该依赖涉及的属性单独拆成一个关系模式
- 剩余属性保留为一个关系模式
- 反复检查,直到满足要求
注意一点:考试时如果题目没说“保持函数依赖”,优先保证无损连接;如果说了,要尽量让每个函数依赖都被某个分解后的模式覆盖。
5. 数据库设计:E-R 图画法及 E-R 图转关系模式的规则
数据库设计大题几乎是每学期必考。它不像范式题那样有严格的算法,但评分标准非常细,画错一个实体、漏标一个联系、转换关系模式时少一个外码,都会被扣分。这一节把完整的流程和规则整理出来。
5.1 六个阶段的“得分点”浓缩版
数据库设计的六个阶段是:
- 需求分析:产出数据字典、数据流图
- 概念结构设计:产出 E-R 图(核心考点)
- 逻辑结构设计:E-R 图转为关系模式(核心考点)
- 物理结构设计:索引、存储结构设计
- 数据库实施:建库、数据装载
- 数据库运行与维护:监控、调整、备份恢复
简答题如果考到“为什么要先设计概念模型再设计逻辑模型”,核心答法是:概念模型能真实反映现实世界的信息结构和信息流动,不依赖具体数据库管理系统;逻辑模型则需要考虑数据模型的特点。先画 E-R 图,相当于在现实世界和计算机世界之间加了一层缓冲,能减少设计失误。
5.2 E-R 图三要素:实体、属性、联系
E-R 图中:
- 实体用矩形框:比如“学生”“课程”“教师”
- 属性用椭圆框:比如“学号”“姓名”“性别”。主码属性下画下划线
- 联系用菱形框:比如“选修”“讲授”。联系也要有属性(比如成绩是“选修”联系的属性,不是学生的属性)
画 E-R 图有一个常见的错误:把“成绩”(Grade) 当作学生或课程的属性。成绩是学生和课程发生“选修”联系时产生的,应该作为联系“选修”的属性。这是我当年考试差点丢分的地方,希望大家别再犯。
联系的类型一定要判断准确:
- 一个学生可选多门课程,一门课程可有多个学生选择 → 学生与课程是 m:n 联系
- 一个班级有多名学生,一个学生属于一个班级 → 班级与学生是 1:n 联系
- 一个系有一名系主任,系主任只属于一个系 → 系与系主任是 1:1 联系
5.3 E-R 图转关系模式的黄金规则
这一步的得分点非常明确,就按下面三条规则来:
- 实体转换为一个关系模式:实体的属性就是关系的属性,实体的码就是关系的码
- 1:1 联系:可并入任一端实体对应的关系模式,另一端加外码
- 1:n 联系:把“一”端的码加入“多”端实体对应的关系模式作为外码
- m:n 联系:独立建立一个关系模式,包含两端实体的码和联系自身的属性;两端实体的码作为外码,联合起来作为主码
有一个容易忽略的细节:当联系的属性很多,或者需要单独查询该联系时,即使是 1:n 联系,也可以为联系单独建立关系模式。如果题目没有特殊要求,按常规规则处理即可。
比如“学生选课”转关系模式:
- Student(Sno, Sname, Ssex, Sage)
- Course(Cno, Cname, Credit)
- SC(Sno, Cno, Grade),主码为 (Sno, Cno),Sno 和 Cno 分别为外码
画图和转换时,注意主码属性必须加下划线,外码要标注出来,否则阅卷老师容易找不到你的对应关系。
6. 事务、恢复与并发控制:必考概念与调度判断题的破解方法
最后一个大模块,也是不少同学觉得“玄学”的部分。数据库系统的可靠性和并发性是这门课区别于普通文件管理系统的关键,期末必然涉及。
6.1 ACID 四大特性要能说清“由谁保证”
事务是数据库操作的基本逻辑单位,具有四个特性:
- 原子性(Atomicity):事务要么全做,要么全不做,靠日志实现(Undo 日志)
- 一致性(Consistency):事务执行前后数据库完整性约束不被破坏,靠应用正确性和完整性约束保证
- 隔离性(Isolation):并发事务之间相互隔离,不互相干扰,靠并发控制机制保证
- 持久性(Durability):事务一旦提交,修改永久生效,靠日志(Redo)和数据库备份恢复机制保证
简答题如果让你“说明 DBMS 如何保证事务的 ACID”,要答到这一层,不能只说“事务是原子且持久的”,必须点出背后的机制。
6.2 故障恢复:日志先写原则和三类故障的处理
数据库可能遇到三类故障:
- 事务故障:比如除零、死锁中断,只需撤销该事务未完成的操作 → UNDO
- 系统故障:比如断电、操作系统崩溃,内存数据丢失但磁盘未损坏 → 对已提交的 REDO,对未提交的 UNDO
- 介质故障:比如磁盘损坏 → 装入备份 + 用日志重做已提交事务
无论哪种故障,DBMS 都遵循一个核心原则:日志先行(Write-Ahead Logging)。即先写日志,再写数据库。因为日志在磁盘上,数据库修改可能只在内存缓冲区。如果系统崩溃,可以依据日志判断哪些操作已提交、哪些需要撤销。
考试常考的判断题是“事务提交后立即写入数据库才算持久化”。这个说法不对。正确做法是:事务提交时,把日志记录写到磁盘(持久化日志),数据库本身可以稍后写入。恢复时靠日志重做即可。
6.3 并发控制:两段锁协议与可串行化判断
并发控制的核心是封锁机制:
- 排他锁(X 锁):写锁,事务对数据加 X 锁后才可读写,其他事务不能加任何锁
- 共享锁(S 锁):读锁,事务对数据加 S 锁后才可读,其他事务可加 S 锁,不能加 X 锁
三级封锁协议解决不同问题:
| 协议 | 要求 | 解决的问题 |
|---|---|---|
| 一级 | 修改前加 X 锁,事务结束才释放 | 丢失修改 |
| 二级 | 一级 + 读取前加 S 锁,读完即释放 | 丢失修改、读脏数据 |
| 三级 | 一级 + 读取前加 S 锁,事务结束才释放 | 丢失修改、读脏数据、不可重复读 |
两段锁协议(2PL):事务分两个阶段——加锁阶段和解锁阶段,加锁阶段不能解锁,解锁阶段不能加锁。2PL 能保证冲突可串行化,但可能产生死锁。严格两段锁在事务提交前不释放任何锁,能进一步防止级联回滚。
判断两个并发调度是否冲突可串行化的通用步骤:
- 画出冲突操作(不同事务对同一数据的一个写操作与另一个写/读操作,且至少一方是写)
- 根据冲突操作构造优先关系图
- 如果图中存在环,则不可串行化;如果无环,则冲突可串行化
以 T1 和 T2 的四个操作举例:
T1: read(A) write(A) read(B) T2: read(A) write(B)先画事务之间的依赖:A 的读写 T1→T2,B 的写操作 T2→T1,环出现,因此这个调度不可串行化。
这类题目一定要动手画图,不要心算。环的判断出错的概率在考场上很高。
7. 最后两周的复习节奏与防丢分清单
前面的知识点覆盖了课程主干。如果你已经是考前两周的状态,这里给出我实际用过的复习安排和丢分点复盘,可以直接抄作业。
7.1 两周复习路线参考
第一周:按模块过基础
- 第 1~2 天:关系代数 + SQL 单表/多表查询,每天 10 道题起步
- 第 3~4 天:嵌套查询 + 视图 + 触发器 + 完整性/安全性简答
- 第 5~6 天:函数依赖 + 范式判断 + 模式分解,集中刷课后题
- 第 7 天:E-R 图设计题专项,练习画图速度和规范
第二周:以卷带练
- 每天一套往年真题或模拟卷,严格限时
- 每套卷子必须分析失分结构,回到课本对应章节查缺补漏
- 考前一晚:只看错题本和本章笔记,不做新题
7.2 考场丢分高频原因
根据我批改作业和观察同学考后复盘的经验,最常见的丢分点集中在以下几个方面:
- SQL 中 GROUP BY 和 HAVING 使用的边界不清:WHERE 和 HAVING 混用
- 关系代数连接条件遗漏:自然连接写出来却少写同名属性比较,导致多了重复列
- 范式判断只写结论不写依据:比如“属于 2NF,因为不存在非主属性对码的部分函数依赖”,要写完整才算稳
- E-R 图联系属性位置放错:联系属性写成实体属性
- 可串行化判断只列操作顺序,不画优先图,导致环判断失误
- 事务恢复题没有区分“已提交 REDO、未提交 UNDO”
还有一个心态上的建议:考试时遇到 10 分钟内没思路的题,先跳过做后面的。数据库题目往往题干信息量大,后做可能反而会想通前面卡住的部分,因为知识之间是关联的,写到后面常常会触发前面题目的解题灵感。
7.3 两个亲测有效的复习辅助技巧
第一个技巧是自己给自己讲题。每做完一道范式分解题,合上答案,把“为什么候选码是这个”“为什么第一步要拆这个依赖”讲一遍,能够清楚发现自己是不是真的理解了。能讲明白的题才是真会的题,只看懂答案的题到考场上换一个形式大概率还是不会。
第二个技巧是做错题归因表。每次做错题,在旁边标注错误类型,比如“SQL 语法错误”“关系属性看漏”“范式判定步骤遗漏”“考试时间分配失误”。坚持一周,你会非常清楚自己在哪一类问题上的错误率最高,后面复习就有明确的靶子。
最后再分享一个我个人用了很多次的小习惯:考前把课本目录抄在白纸上,对每个章节给自己打掌握度分数(1~5 分),低于 3 分的章节重点突击。这个方法花不了十分钟,却能让最后冲刺阶段的复习顺序清晰很多,也能有效缓解“哪都复习了又哪都没复习透”的焦虑感。