
很多人学《数据库系统概论》这套书都会被课后题卡住。王珊老师的第五版是好多高校本科数据库课程的指定教材网上流传的答案版本五花八门有的只有最终结果没有推导过程有的干脆是错的。我当年备考时把第五版的习题仔细过了一遍后来又用过第六版做过对比这套教材的课后题质量确实高——它不考死记硬背而是逼你把关系代数、SQL、范式、事务并发这些核心概念真正想明白。这篇内容我不打算罗列答案而是把习题里最有区分度的几类题目拆开讲透顺带把大家最容易纠结的知识点揉碎了说清楚。1. 教材版本差异与习题应对策略1.1 第五版和第六版到底差在哪先解决一个很实际的问题很多人手里是第五版但网上搜到的答案有不少是第六版的两版章节顺序和题号不完全一致照抄就会出现“对不上号”的情况。第五版2014年出版的核心结构是11章加附录从绪论、关系数据库、SQL、安全性、完整性到关系数据理论、数据库设计、查询处理优化、事务管理、并发控制、数据库恢复最后还有数据库新技术展望。第六版2018年出版在整体框架上延续了第五版主要改动集中在两方面一是部分章节的例题和表述做了更新更贴近现代数据库产品的实际行为二是每章课后习题做了增删调整比如在关系代数部分增加了更复杂的查询表达练习在并发控制章节补充了关于隔离级别的讨论。如果你用的是第五版找答案时要认准“数据库系统概论第五版课后习题答案”字样核对章节标题是否一致。第六版答案里有个别题在第五版中不存在对应关系是第五版第2章的习题在第六版可能挪到了第3章SQL章节的题号普遍有偏移。我的建议是不要只看题号要把题目内容抄下来对照确认完全一致再参考答案。1.2 课后习题在考试中的分量从应试角度看课后习题基本就是期末考试的“题库原型”。我统计过几所高校的数据库期末考试卷大约60%到70%的大题能在课后习题里找到影子尤其是关系代数表达式、SQL语句编写、范式判断与分解、封锁协议分析这四类题型几乎每学期必考。不过要提醒一点老师出题通常不会原封不动照搬而是会做参数替换或场景扩展。比如课后题里是“查询选修了全部课程的学生”考试时可能变成“查询选修了全部必修课的学生”或者加上“且成绩大于80分”的条件。所以做题时不能背答案要把解题方法真正理解特别是关系代数的思路要活。2. 关系代数与SQL习题的破解方法2.1 关系代数题的通用解题套路关系代数是数据库理论的基石也是很多人觉得抽象的地方。第五版第2章的习题集中在选择、投影、连接、除运算这几类操作上其中除法运算的题目错误率最高。除运算也就是“查询包含全部某类对象”的题目是关系代数里的头号难点。我总结了一个三步法第一步确定被除关系、除数关系和结果关系。被除关系通常是“包含所有属性”的那个大表除数关系是“限定条件”的那个小表结果关系是“满足条件的主体”。第二步检查属性相容性。被除关系和除数关系必须在除运算涉及的属性上有相同的域。比如“查询选修了全部课程的学生”被除关系是选课表学号课程号除关系是课程表课程号两者在课程号上相容。第三步写表达式并验证。用自然语言描述“哪些学号在选课表中出现的课程号集合包含了课程表中的全部课程号”然后对应写出除法表达式最后代入几组数据验证结果。以经典题目“查询选修了全部课程的学生学号和姓名”为例正确答案是先求学生与选课的自然连接得到学号姓名课程号再对课程号做除法。但很多人在第一步就错了——他们直接用选课表除以课程表得到的是学号丢失了姓名信息要得到姓名还得再和学生表连接。这类细节正是考试扣分点。2.2 SQL复杂查询的分步拆解SQL题在第五版第3章占据了大量篇幅从简单的单表查询到嵌套查询、集合查询、数据更新题型非常全面。做SQL题时最常见的错误是逻辑混乱层级一多就不知道先写哪部分。我的建议是先用自然语言把查询需求拆成若干子任务再逐步翻译成SQL。以典型的“查询平均成绩大于80分的学生学号和平均成绩”为例合理的思考路径是先按学号分组然后对分组后的记录施加平均成绩大于80的筛选条件最后输出学号和平均值。关键判断是平均成绩的筛选不能放在WHERE子句中因为WHERE在分组之前执行此时还没有平均成绩可用必须用HAVING子句在GROUP BY之后筛选分组。另一个高频考点是相关子查询。例如“查询选修了学号为201215121的学生所选全部课程的学生姓名”这类题目需要用到NOT EXISTS的双重否定技巧。很多初学者不理解为什么“全部”要用NOT EXISTS表达我用一个生活化类比解释如果你想知道“一个学生是否没有缺任何一门指定课程”最直接的办法是检查“是否存在一门指定课程这个学生没选”如果不存在就说明全选了。所以NOT EXISTS 不存在NOT EXISTS的组合就成了表达“全部”的利器。2.3 基于“数据库系统概论第六版”的新题动向如果你手头有第六版会注意到新版在SQL习题中增加了一些更贴近实际开发的场景比如窗口函数的简单应用、WITH子句的公共表表达式等。这些在第五版中基本没有涉及但如果你参加的是数据库系统工程师考试或研究生入学考试建议把第六版的新增习题也刷一遍。这里多说一句数据库系统工程师考试软考中级的下午题也有SQL和关系代数的内容但更偏向实际应用。王珊教材的习题偏重理论两者结合复习效果更好先刷课后题打基础再用软考真题练应用场景。3. 范式判断与模式分解的高频考点3.1 函数依赖与候选键的确定第6章关系数据理论是整套教材的理论高地也是考试的分水岭。课后习题里确定候选键、判断范式级别、进行无损分解和保持函数依赖的分解这三类题目几乎每年必考。候选键的确定要抓住一个核心原则候选键的闭包必须包含全部属性并且候选键本身没有多余属性。我可以分享一个快速判定技巧如果一个属性从未出现在任何函数依赖的右侧那它必定属于每个候选键如果某个属性从未出现在任何函数依赖的左侧那它必定不属于任何候选键。以课后经典题为例关系模式RU, FU {A, B, C, D, E}F {A→BC, CD→E, B→D, E→A}。这题的候选键不唯一很多同学只会找到第一个候选键就停手。正确的做法是穷举所有可能的属性组合确保每个候选键都不能再删减属性。A的闭包是{A, B, C, D, E}所以A是一个候选键又因为E→AE的闭包也是全集所以E也是候选键同理CD的闭包是全集且CD的任意真子集闭包都不是全集所以CD也是候选键。最终候选键有三个A、E、CD。这个例子说明一个道理候选键不只有一个做题时必须完整枚举漏掉任何一个都不算对。3.2 范式级别判断的快速判定法判断范式级别时我推荐按“从低到高排除法”来操作第一步检查是否存在非主属性对候选键的部分函数依赖存在则为1NF。 第二步若不存在部分依赖再检查是否存在非主属性对候选键的传递函数依赖存在则为2NF。 第三步若不存在传递依赖再检查是否存在主属性对候选键的部分或传递依赖存在则为3NF。 第四步若所有函数依赖的左部都是超键即BCNF要求则为BCNF。很多同学混淆了3NF和BCNF的区别。关键差异在于3NF容忍“主属性对候选键的传递依赖”而BCNF完全不允许任何属性无论主属性还是非主属性对候选键的传递依赖。换个说法3NF只约束非主属性BCNF约束所有属性。课后题里常出现这样的模式RA, B, CF {AB→C, C→A}。候选键是AB和BC。这里没有非主属性A、B、C全是主属性所以至少是3NF。但C→A的左部C不是超键所以R不是BCNF。这种“是3NF但不是BCNF”的关系模式正是考试的经典陷阱。3.3 无损分解与保持依赖的实操验证关于分解课后习题里几乎必然会考“判断分解是否无损”和“判断分解是否保持函数依赖”。前者用chase追踪算法验证后者逐个检查函数依赖是否在分解后的某个关系模式中被保持。无损分解的chase算法看起来复杂其实有简化路径。以二分分解为例如果分解ρ {R1, R2}则分解无损的充要条件是R1∩R2→R1或R1∩R2→R2中至少有一个成立这里的→是函数依赖闭包中的蕴含关系。也就是说两个子模式的公共属性必须是其中一个子模式的超键。这个结论可以快速口算验证不用画复杂的chase表。举课后题的例子RA, B, CF {A→B, B→C}分解为R1A, B和R2B, C。公共属性是BB→C成立因此分解无损。但如果验证保持依赖可以看到A→B在R1中成立B→C在R2中成立两个依赖都被保留所以这个分解既无损又保持依赖。再来一个坏例子同样RA, B, CF同上分解为R1A, C和R2B, C。公共属性是C但C无法决定A或B的任何超键因此分解有损会丢失A→B的依赖连接信息。这类对比题只要掌握判定条件正确率可以做到100%。4. 事务、并发控制与恢复的必考题型4.1 事务ACID特性与SQL实现第11章事务管理的内容在课后习题里以概念题和计算题两种形式出现。概念题考察ACID四个特性的理解和区分计算题则集中在故障恢复和并发调度正确性上。关于ACID大家容易混淆的是一致性和隔离性。一致性是指事务执行前后数据库的完整性约束不被破坏隔离性是指多个事务并发执行时互不干扰。有一个经典类比如果两个人同时操作同一个银行账户无论他们存取款的顺序如何交错只要每个事务本身是原子性的账户余额的最终值必须等价于某个串行执行的结果——这就是隔离性保证的而无论怎么交错账户余额不能出现负数如果余额约束是大于等于零这就是一致性保证的。课后习题中会要求用SQL写出事务的示例比如“利用T-SQL将一笔金额从账户A转账到账户B”。标准写法包含BEGIN TRANSACTION、UPDATE两次、IF判断和COMMIT/ROLLBACK。这类题的考点是必须把两个UPDATE放在同一个事务中否则中间出错时会出现资金凭空消失的严重问题。4.2 可串行化调度冲突等价判断并发控制章节的习题里判断一个调度是否可串行化是重中之重。方法是画出冲突对读写了同一数据项的、来自不同事务的操作对然后构造优先图。如果优先图无环则调度是冲突可串行化的。以课后题常见的三类操作序列为例事务T1read(A), write(A), read(B), write(B)事务T2read(A), write(A), read(B), write(B)任何一个包含T1和T2交替操作且对同一数据项产生了读写冲突的调度判断其是否为可串行化只需要关注冲突对中的操作顺序。如果T1的write(A)在T2的read(A)之前则优先图中有一条T1→T2的边如果T2的write(B)在T1的read(B)之前则存在T2→T1的边两条边同时存在就形成环判定为不可串行化。这个考点在数据库系统概论第五版第10章并发控制的习题中反复出现建议把所有调度序列都用优先图法验证一遍练到能心算为止。4.3 日志恢复先写日志还是先写数据恢复章节的核心考点是日志文件在故障恢复中的作用。课后习题经常给出一个操作序列要求根据日志判断恢复时哪些事务需要REDO、哪些需要UNDO。判定原则就两条如果事务的COMMIT记录已经写入日志但数据页还没来得及写入磁盘则系统重启后需要REDO也就是重做事务的所有写操作。如果事务既没有COMMIT也没有ABORT记录说明事务未完成系统重启后必须UNDO也就是撤销它已经写入磁盘的修改。还要注意先写日志原则WALWrite-Ahead Logging日志必须先于数据页写入磁盘。这个原则保证了系统在崩溃后能够通过日志完成恢复不会出现“数据改了但日志没记”的不可恢复状态。课后题中常见的陷阱是某个事务已经写了数据页但没有COMMIT记录此时系统崩溃。不少同学认为这个事务已经修改了数据应该REDO。正确答案恰恰相反——没有COMMIT记录的事务无论它写了多少数据页都必须UNDO。因为在数据库的语义中只有提交的事务才被认为是有效的。4.4 两段锁协议与死锁处理并发控制的另一个考试阵营是封锁协议。两段锁协议2PL要求每个事务分两个阶段增长阶段只能加锁不能解锁收缩阶段只能解锁不能加锁。满足两段锁协议的事务调度一定是可串行化的。课后习题会让你分析某个事务的加锁解锁顺序是否满足两段锁协议以及不同封锁协议一级、二级、三级能防止什么问题。这里有个快速记忆法一级封锁协议修改前加X锁直到事务结束。防止丢失修改。二级封锁协议在一级基础上读前加S锁读完即释放。防止丢失修改和读“脏”数据。三级封锁协议在二级基础上S锁保持到事务结束。防止丢失修改、读“脏”数据和不可重复读。关于死锁课后习题常要求判断系统处于死锁状态的依据或者给出解除死锁的方法超时法、等待图法、牺牲法等。注意区分系统死锁与活锁的概念活锁是某个事务永远等待系统整体没有死锁但某个事务被饿死死锁则是多个事务循环等待谁也执行不下去。两者处理方式完全不同。5. 自测与复习路径规划5.1 从课后题到期末卷的映射练习刷完课后题之后建议按照考试题型做一次自测。我可以给一个实用的复习路径参考第一轮按章节顺序做课后题标记出错题和不确定的题。这一轮不追求速度但要求每题都写出完整的推导过程不要直接看答案。第二轮把错题归类。关系代数类错误集中练第2章对应习题SQL类错误重刷第3章范式类错误回到第6章。错题归类的核心价值在于暴露知识盲区而不是盲目刷题。第三轮模拟考试。找几份往年的期末考试卷或数据库系统工程师真题限定2小时完成。注意模拟时不要翻书答完后再对着课后题解析核对。5.2 自测题精选与参考答案思路这里我挑三道代表性自测题检验一下自己是否真正掌握了关键考点。自测题一设有关系RA, B, C和SB, C, D请用关系代数表达式查询“R和S中B值相同的元组对”。思路分析这题考察自然连接和条件连接的区别。若查询“B值相同”并输出两表所有属性应使用条件连接R ⋈ (R.BS.B) S而不是自然连接因为自然连接会自动合并相同属性名B列、C列会合并为单列不符合题目“输出元组对”的要求。如果题目要求输出两表全部属性则需对连接后的结果用重命名操作区分B、C列。这类“一字之差”的条件在考试中很容易丢分。自测题二关系模式RA, B, C, DF {A→B, B→C, C→D}判断R属于第几范式。思路分析候选键为A存在A→B→C的传递依赖B不是候选键因此R不是3NF而是2NF。进一步分析没有非主属性对候选键的部分依赖所以R满足2NF。这是课后题里非常典型的“部分依赖和传递依赖区分”训练。自测题三给定调度ST1读AT2读AT1写AT2写AT1提交T2提交。判断该调度是否可串行化。思路分析考察冲突对T1的read(A)与T2的write(A)无冲突读与写在“先读后写”时后写会覆盖但不会导致读到的值不同这里需要仔细判断——事实上读和写是冲突操作无论顺序如何读写同一数据项都是冲突的。T1 read A 和 T2 read A 不冲突两个读不冲突。T1 read A 和 T2 write A 是冲突对且T1的read发生在T2的write之前产生T1→T2的边T2 read A 和 T1 write A 是冲突对且T2的read发生在T1的write之前产生T2→T1的边T1 write A 和 T2 write A 是冲突对产生T1→T2的边T2 write A 和 T1 read A 已分析过综合来看优先图中存在T1→T2和T2→T1两条边形成环因此调度不可串行化。5.3 利用热词扩展学习数据库系统原理与工程师认证在搜索答案解析的过程中很多人会看到“数据库系统原理”“数据库系统原理及应用”这些关联词。它们其实对应不同的教材和课程体系王珊的《数据库系统概论》偏重学院派理论而《数据库系统原理及应用》这类书名更偏向应用型本科教材SQL实践占比更大。如果你是为了应付期末考试以学校指定教材为准即可如果你是自学转行或备考数据库系统工程师建议在王珊这本之外再搭配一本以SQL实践为主的教材两者互补。数据库系统工程师考试软考中级的上午题侧重数据库原理、数据仓库、关系代数、事务管理下午题则侧重SQL编写、数据库设计ER图转关系模式和案例分析。王珊教材的课后题对上午题帮助巨大但下午题还需要额外练习项目实战。我的建议是把课后题当作理论根基把软考真题当作应用检验双线并行。6. 实操中遇到的高频误区与避坑指南6.1 关系代数表达式的等价变换错误做关系代数题时最容易犯的错误是认为选择操作可以任意交换顺序。比如“查询年龄大于20且选修了课程C1的学生姓名”有人写成先投影姓名再选择年龄这样是错误的因为投影后已经没有年龄属性了。正确的顺序是先做选择年龄20和连接学生和选课表再做投影姓名。还有一种常见错误是把自然连接与等值连接混用。自然连接会自动合并同名列而等值连接保留全部列。在输出列数量有要求的题目里这两者的结果可能完全不同。建议在草稿纸上把每次操作后产生的属性列写清楚避免列数对不上。6.2 SQL执行顺序的理解偏差SQL书写顺序和实际执行顺序不一致这是很多人在复杂查询上栽跟头的原因。标准SQL的执行顺序逻辑层面是FROM确定数据源WHERE对源数据逐行过滤GROUP BY按列分组HAVING对分组结果过滤SELECT投影与计算ORDER BY排序LIMIT/OFFSET分页理解了执行顺序就不会再犯“在WHERE里使用聚合函数作为条件”的低级错误也能理解为什么列别名不能在WHERE中直接使用因为SELECT在WHERE之后才执行别名此时还不存在。6.3 范式分解的实现细节关于3NF分解和BCNF分解课后题的参考答案往往只给出最终分解结果省略了中间判定过程。我建议在自测时强制要求自己写出每一步先求候选键再判断范式级别然后找出违反范式的函数依赖最后根据该依赖进行分解并对每个分解后的子模式重复判断直到所有子模式都满足目标范式。BCNF分解需要特别注意初始关系模式即使已经是3NF也可能不满足BCNF。分解后的每个子模式还要继续检查是否存在违反BCNF的函数依赖如果存在必须继续分解形成一棵分解树。很多同学的答案只分解了一层没有继续分解子模式导致结果不满足BCNF的最终要求。6.4 数据库设计题中ER图转换的关系模式数目第7章数据库设计有一类必考题把ER图转换为关系模式。这里有个容易出错的地方一个1:n联系通常不需要单独转换成关系模式而是把“1”端关系模式的主键并入“n”端关系模式作为外键一个m:n联系则必须转换为独立的关系模式其主键由两端实体的主键共同构成。课后题中经常出现“一个系有多个学生一个学生只属于一个系一个学生可选多门课程一门课程可有多个学生选修”的多实体ER模型。正确的转换结果是系系号系名…、学生学号姓名系号…、课程课程号课程名…、选课学号课程号成绩。注意“选课”关系模式的主键是学号课程号成绩属性不能作为主键。这类转换题只要掌握了规则属于稳拿分的题目。6.5 个人实操心得做题节奏与错题本的使用最后分享一点个人体会。数据库课后习题的难度曲线不是线性的第2、3章是入门第6章是理论高峰第10、11章是实际系统设计的延伸。我建议的做题节奏是第2、3章控制在3天内完成第一遍第6章用2天专门攻克第10、11章可以结合生活中的场景比如转账、订票系统来辅助理解效率会高很多。错题本不需要抄题目只需要记录错误类型。我自己的分类是概念混淆型、推导步骤缺失型、SQL执行顺序型、范式判断遗漏型。每种类型积累到一定数量后集中回顾效果比反复刷全题要好得多。这个习惯我后来用在其他科目上同样有效。7. 真题、答案解析与靠谱资源筛选7.1 如何判断网传答案的可靠性网上的数据库系统概论课后习题答案质量参差不齐有的答案是学生自己整理的错误率不低。我判断一份答案是否靠谱有三个标准第一解题过程是否完整。只有最终结果、没有推导步骤的答案价值有限因为数据库习题最重要的是思路而不是那个最终的关系代数表达式或SQL语句。第二关键结论是否符合教材定义。比如候选键的判定、范式级别的结论这些都有明确标准如果一份答案在第6章频繁给出违背教材定义的结论基本可以判断不可靠。第三是否有版本标注。靠谱的答案会明确说明自己对应第五版还是第六版章节标题和题号能对得上。如果一份答案笼统地写“数据库系统概论答案”连版本都不标大概率是拼凑的。7.2 构建属于自己的答案解析我在刷题过程中发现最有价值的东西不是别人给的答案而是自己整理的一份“解题索引”。具体做法是每做完一章习题用一句话概括这道题考察的核心知识点并标注出题陷阱所在。比如第3章某道SQL题可以标注“考点HAVING与WHERE的区别陷阱分组前筛选与分组后筛选的混淆”。这份索引到期末复习时会非常有用。两三个小时就能把整本书的课后题考点过一遍远比重新翻书高效。它还能帮助你建立知识体系的全局观而不是把每一章当作孤立的碎片。7.3 经典教材之外的扩展阅读建议如果学有余力我建议把《数据库系统概念》Abraham Silberschatz等著机械工业出版社作为补充读物。这本书的习题难度比王珊的教材更高尤其是在关系代数和并发控制方面有大量极具挑战性的思考题。数据库系统工程师考试中偶尔会出现超出常规教材范围的题目这些扩展阅读能帮你建立起更坚实的理论框架。另外近年来数据库相关的新技术热点如NoSQL、分布式数据库、云数据库在王珊第五版中只在最后一章略有涉及。虽然期末考试通常不考这些内容但在面试或实际工作中这些反而是高频话题。建议在学习教材之余关注一下主流数据库产品的发展动态让理论与现实接轨。这套教材的课后题我从学生时代刷到工作后带新人至今仍然认为它们是数据库理论入门的最好训练材料。那些看似枯燥的关系代数表达式和范式分解实际上是在培养一种极其重要的建模思维——如何把现实世界的复杂业务抽象成严谨、可验证的数据模型。这种能力一旦建立不论以后用MySQL、PostgreSQL还是国产数据库底层逻辑都是相通的。刷题的时候多问自己一句“为什么要这样设计”收获会大得多。