首页 / 资讯中心 / 文章详情

数据库系统概论习题答案高效利用:从关系代数到范式分解

数据库系统概论习题答案高效利用:从关系代数到范式分解 ★ FEATURED ARTICLE
简介数据库系统概论第五版习题答案覆盖教材第1章绪论至第16章数据仓与联机分析处理技术对应王珊、萨师煊主编教材的全部章节面向高校计算机相关专业学生、考研备考者及数据库课程教师。答案对每章核心概念与课后问题作了细致解答如第1章中对数据、数据库、数据库管理系统、数据库系统等概念给出定义并结合银行账户交易、电商订单等实例加以解析同时辨析文件系统与数据库系统的区别与联系阐述使用数据库系统的优点与适用场景便于读者理解基础原理并建立整体框架。资源为单个docx文档压缩包大小34KB下载后可直接阅读或打印适合配套教材逐章巩固、考前快速回顾以及教学备课参考尤其有助于掌握关系数据库、数据库设计、恢复技术与并发控制等重难点。目前已有7544人学习下载是系统梳理数据库理论知识的实用辅助资料。1. 这本习题答案为什么值得逐章拆解很多人拿到《数据库系统概论第五版》的习题答案第一个动作就是对答案错了就改对了就翻页。但如果你只做这一步这本题答案的价值基本被浪费掉了。它真正值钱的地方在于逼你把每个概念在纸上完整算一遍关系代数写不出来说明你没理解连接与投影的作用域范式分解结果不对说明你对函数依赖的传递链还是黑匣子并发调度的优先级画错说明你对冲突操作的定义根本没建立。这篇内容不教你抄答案而是把课后题拆成一套可以反复自测、能对应考试考点的复习动作。适合正在备课程期末、准备考研初试或者想系统补一遍关系型数据库理论基础的开发者。做这本题答案的前提是“先做题再对答案”这个顺序不能反。一旦先看了答案你的大脑会进入记忆模式而不是推演模式考场上换一个参数、换一个表名立刻翻车。下面几章我会从通用解法框架、重点题型精讲、高频坑位排查三个角度把这本题答案变成你手里真正能用的复习工具。2. 破解课后题的通用解法框架先定位考点再选解题路径2.1 一道课后题的正确打开方式题型决定解题顺序拿到任何一道课后题先别急着写用十秒钟判断它属于哪一类。这本书的课后题大致可以归成五类概念简答题、关系代数表达式题、SQL查询题、范式推导题、数据库设计题。每一类的解题顺序完全不一样混着做很容易把时间耗在无效步骤上。我一般会按下面的表来判断题目类型和切入路径题目类型考点定位推荐解题顺序概念简答题定义、术语、分类先写关键词再展开成完整句子关系代数表达式题选择、投影、连接的作用域先拆查询条件再排操作顺序SQL查询题分组、嵌套、连接语义先写逻辑思路再写语句范式推导题候选键、函数依赖、分解算法先求候选键再做范式判定设计题实体、联系、E-R图合并先画局部E-R图再合并消除冲突为什么先定位题型因为这本书的习题答案里同一个表结构会被反复使用但每类题对表结构的处理方式不同。关系代数题关注的是操作顺序SQL题关注的是语义等值范式题关注的是依赖关系。你把类型认错了后面的步骤基本全错。定位完题型之后我的做题顺序固定为五步。第一步遮住参考答案把题目完整抄在草稿纸上包括表结构和查询条件第二步用红笔圈出所有让你犹豫的地方这些地方就是你的知识缺口第三步不翻教材凭记忆写完整答案第四步打开参考答案逐条对照第五步把不一致的地方写进错题记录并标注考点。这五步里最容易偷懒的是第五步很多人对完答案就合上书导致同一个坑下次继续踩。注意习题答案的正确用法是“校对自己的思维过程”不是核对最终结果。结果对了但过程绕远考试时一样会超时。2.2 从题目回看教材核心章节的知识地图与习题分布这本教材的课后习题分布是有规律的。很多时候你觉得自己不会做不是因为题目难而是因为没把这章的核心考点理清楚。下面这张表是我按章节整理的考点与题型对照做题前先扫一眼心里就有底了教材章节核心考点高频题型常见失分点关系数据库关系完整性、关系运算概念简答、关系代数运算闭包与作用域混淆SQL语言嵌套查询、分组统计SQL书写、改错聚合函数与WHERE混用关系数据理论函数依赖、范式判定候选键求解、分解部分依赖与传递依赖漏判数据库设计E-R图设计、逻辑转换设计题联系类型识别错误恢复与并发日志、两段锁协议简答、调度分析冲突操作漏判每个章节的习题答案本质上是这章知识的压缩包。比如第二章的关系代数题每一道都在反复训练你同一件事如何把一个自然语言查询翻译成有序的操作序列。答第3章SQL题时你会发现很多查询可以用子查询、也可以用连接答案里通常只给一种写法但考试时往往会要求你写出另一种。所以不能只背答案里的写法还得追问一句“还有没有等价写法”。我用这本书带复习时有一条原则每道做错的题必须回到教材的对应小节把定义重新抄一遍。比如你错在“无损连接分解”上那就回到范式那一节把分解算法从头看一遍。这个动作叫“错题回挂”它能让习题答案的价值放大好几倍。只对答案不回挂教材做一百道题也是原地踏步。2.3 构建自己的答案版本先闭卷做再对照答案修订这本题答案里有一部分题是“多解题”比如3NF分解的结果不唯一不同的分解路径可能得到不同的关系模式。如果你直接背标准答案考试时一旦题目参数变化你连从哪下手都不知道。所以我建议你构建一份属于自己的答案版本而不是把书后答案当成唯一真理。操作方法是这样的。第一遍闭卷做题时把每一步推导都写在纸上哪怕丑、哪怕乱也要保留痕迹。第二遍对照参考答案时不要划掉自己的错误过程而是在旁边用另一种颜色的笔写正确路径并注明“我当时为什么卡住”。第三遍把这道题浓缩成一个考点卡片正面写题目类型背面写解题入口。下面是我用过的一个修订记录模板你可以直接抄到笔记软件里题目位置我的答案要点参考答案要点差异原因考点归类第3章第5题用GROUP BY先分组用子查询先过滤没注意WHERE不能接聚合SQL执行顺序第6章第8题直接分解成两个关系需要先判断候选键漏掉函数依赖闭包候选键求解这个模板的价值在于强制你写出差异原因。很多情况下你会发现自己的答案和标准答案结果一样但思路完全不同这时差异原因写“思路不同结果等价”也是一种收获。它说明你已经理解了这道题的本质只是在路径选择上做了不同的取舍。做完修订之后把这章节的考点频率统计一下你会发现有些考点反复出现比如“候选键求解”“无损连接分解”“SQL分组过滤”。这些高频考点就是你复习时优先投入时间的区域而不是按章节顺序平均用力。3. 重点章习题精讲关系代数、SQL与范式分解的解题步骤3.1 关系代数表达式把自然语言查询翻译成操作序列关系代数题的正确答案本质上是一组有序的操作序列。很多人在这一步翻车是因为把自然语言里的每个条件单独翻译成一个小操作然后随便拼在一起完全不考虑操作之间的依赖关系。我拿一个最常见的题目结构来说明。假设有三个关系Student(Sno, Sname, Ssex, Sage, Sdept)Course(Cno, Cname, Cpno, Ccredit)SC(Sno, Cno, Grade)。题目要求查询“计算机系年龄小于20岁的学生的学号与姓名”。我的解题步骤是第一步找出题目里的所有约束条件这里是“计算机系”和“年龄小于20岁”它们都是对Student关系的筛选可以合并进同一个选择操作。第二步确定需要输出的列是Sno和Sname它们来自Student关系。第三步先做选择再做投影写成下面的形式σ(SdeptCS AND Sage20)(Student) π(Sno, Sname)(σ(SdeptCS AND Sage20)(Student))为什么先选择后投影因为选择操作会扫描整张表的所有列投影操作则会裁剪列。如果你先投影掉Sdept和Sage后面再想按这两个条件筛选数据已经没了这就是经典的“投影过早”错误。虽然有些DBMS优化器会自动做等价变换但手写关系代数时你按先选择、后投影的顺序写阅卷时最容易拿全分。再看一个带连接操作的题目查询“选修了课程号为C02且成绩大于90分的学生的姓名”。这道题涉及SC与Student两个关系解题顺序是步骤操作说明1在SC上执行选择筛选CnoC02 AND Grade90缩小参与连接的数据量2与Student做自然连接连接条件是Sno相等3在连接结果上投影只输出Sname这样做的理由是尽可能缩小中间结果。如果你先把两个关系做笛卡尔积再筛选虽然逻辑上没错但中间结果会膨胀很多。手写关系代数时尽管没有执行成本的概念阅卷老师也默认你按“先缩行、再扩列”的顺序组织表达式。最后提醒一种常见题型查询“选修了全部课程的学生学号”。很多人会用连接和分组来做但正确做法通常是除法运算或者用“不存在一门课程没被该生选修”的双重否定来表达。这道题在习题答案里出现频率很高值得专门记一下它的标准写法。3.2 SQL作业题嵌套查询与分组统计的切入点SQL题看的是语义准确性和执行效率意识。书后答案通常给一种标准写法但实际做题时我会先写一个逻辑版本再优化成一个更稳的版本。下面用一道典型的分组统计题说明。题目查询“每门课程成绩最高分的学生的学号、课程号和成绩”。很多人的第一反应是先用GROUP BY取最高分然后再去明细里找对应学生。SELECT sc.Sno, sc.Cno, sc.Grade FROM SC sc JOIN ( SELECT Cno, MAX(Grade) AS MaxGrade FROM SC GROUP BY Cno ) t ON sc.Cno t.Cno AND sc.Grade t.MaxGrade;这段SQL的逻辑是内层子查询按Cno分组算出每门课的最高分外层查询再通过连接条件把最高分对应的明细行找出来。这里的JOIN连接条件有两个Cno相等、Grade等于最高分两个条件缺一不可。如果只连接Cno会把每门课的所有成绩行都带出来结果完全不对。有个老生常谈的坑必须注意不要把MAX(Grade)写进WHERE子句比如“WHERE Grade MAX(Grade)”。SQL标准不允许聚合函数直接出现在WHERE中因为WHERE是在分组之前执行的你要求分组后的聚合结果去过滤分组前的行逻辑上互相矛盾。正确位置是HAVING或者子查询里。再看一道典型的嵌套查询题查询“没有选修C01课程的学生姓名”。SELECT Sname FROM Student WHERE Sno NOT IN ( SELECT Sno FROM SC WHERE Cno C01 );这个写法思路很直接先在SC里找出选修了C01的学生学号再从Student里排除这些人。但这里有一个特别隐蔽的坑如果SC表里Sno列存在NULL值NOT IN的返回结果可能为空集导致整个查询查不到任何学生。这是书中习题答案不会特别标注、但实际执行时最容易踩中的雷。解决方案是把NOT IN改成NOT EXISTSSELECT Sname FROM Student s WHERE NOT EXISTS ( SELECT 1 FROM SC sc WHERE sc.Sno s.Sno AND sc.Cno C01 );NOT EXISTS是逐行相关子查询对NULL的处理更安全而且语义更清晰。做题时只要看到NOT IN我第一反应就是检查子查询列里有没有可能混入NULL。如果题目没有声明该列非空优先用NOT EXISTS版本稳妥不丢分。3.3 范式分解的判定顺序从函数依赖到无损连接范式题是这本书里理论性最强的一块也是习题答案占用篇幅最大的部分。做这类题顺序比计算重要。我总结了一条固定路线先求候选键再做范式判定最后执行分解并验证。拿一个经典的习题结构来演示。假设关系模式R(学号, 系名, 系主任, 课程号, 成绩)函数依赖集为{学号→系名, 系名→系主任, (学号,课程号)→成绩}。要求判断R属于几范式并将其分解到3NF。第一步求候选键。候选键要能函数决定所有属性。这里学号能决定系名和系主任但决定不了课程号和成绩课程号单独也决定不了其他属性。只有学号和课程号组合在一起才能推导出全部属性所以候选键是(学号,课程号)。第二步判断范式级别。检查每个非主属性对候选键的依赖方式。系名和系主任只依赖于学号不依赖于课程号说明它们对候选键存在部分函数依赖这直接违反了2NF的要求。因此R只属于1NF需要分解。第三步执行分解。先把存在部分依赖的属性拆出去R1(学号, 系名, 系主任)R2(学号, 课程号, 成绩)。接着检查R1R1的候选键是学号函数依赖中有系名→系主任系主任不直接依赖于学号存在传递依赖所以R1不满足3NF继续拆成R11(学号, 系名)和R12(系名, 系主任)。R2的关系模式中所有非主属性都完全依赖候选键且没有传递依赖满足3NF。第四步验证无损连接。一个简单的验证方式是看分解后的关系之间是否保留了足够的信息用于还原原关系。常见的方法是追踪表法但做题时可以快速检查R11和R12通过系名连接可以还原R1R1和R2通过学号连接可以还原R因此这个分解是无损的。保持函数依赖方面原有的三个函数依赖都被保留在某个分解关系中所以这个分解同时满足无损连接和保持依赖。范式等级判定核心本题判定结果1NF属性都是原子值满足2NF非主属性完全依赖候选键不满足存在部分依赖3NF无非主属性传递依赖不满足R1存在传递依赖BCNF所有决定因素都是候选键分解后各关系满足最后补充一个经验别在开始分解时急于动手先花两分钟把候选键求对。候选键求错后面的所有判定全部作废。而候选键求解又依赖函数依赖闭包所以做题真正的第一步是写出函数依赖集合并检查有没有遗漏推导比如“学号→系名”和“系名→系主任”可以推出“学号→系主任”这个传递依赖就是拆分的依据。3.4 事务并发题两段锁协议的可串行化判断并发控制是期末和考研都喜欢考的小题它出现在习题答案里时通常是一串事务的读写操作序列让你判断是否冲突可串行化。先记三个冲突操作的定义不同事务对同一数据项做“写-读”“读-写”“写-写”操作时如果至少有一个是写那么它们就是冲突的。“读-读”不冲突可以并发执行。判断一个调度是否冲突可串行化的办法是画优先图把每个事务画成一个节点如果事务T1的某个操作与T2的某个操作冲突且T1的操作在T2之前就画一条从T1指向T2的有向边。最后检查图中是否有环有环则不可串行化无环则存在拓扑序调度冲突可串行化。举个例子事务T1执行Read(A)、Write(B)事务T2执行Read(B)、Write(A)调度顺序是T1的Read(A)、T2的Read(B)、T1的Write(B)、T2的Write(A)。检查冲突操作T1的Write(B)与T2的Read(B)冲突且T1在前画T1→T2T2的Write(A)与T1的Read(A)冲突且T2在前画T2→T1。图中出现双向环这个调度不可串行化。如果题目再追问“是否满足两段锁协议”那就需要对锁操作做分析。两段锁协议要求每个事务分两个阶段增长阶段只能加锁不能释放锁收缩阶段只能释放锁不能再加锁。只要某个事务在释放过任何锁之后又申请新锁就违反了协议。做题时我给的建议是把每个事务的加锁、释放列成一条时间线直接在时间线上标出释放位置然后看释放点之后还有没有LOCK请求。这一块的计算量不大但特别容易漏判冲突。我的检查习惯是每个操作对都列出来逐对判断不跳步不要只盯着看起来明显冲突的写写操作读写和写读同样需要关注。4. 习题答案自查与避坑五类常见的翻车现场4.1 先投影后选择把条件列弄丢了现象写关系代数表达式时第一步用了投影第二步再对某个被投影掉的列做选择结果表达式写了一半就卡住因为条件列已经不在投影结果里。原因投影会移除不需要的列但后续的筛选需要用到这些列。典型的场景是先π(Sno, Sname)再σ(SdeptCS)这时Sdept已经被投影裁剪掉选择操作无法执行。解决记住“先缩行再缩列”的顺序。任何时候都要先做选择缩小数据范围再做投影裁剪输出列。如果确实需要在投影后继续筛选那就把条件列也留在投影结果里等到最后再裁掉。检查时看一眼表达式里每个操作引用的列是否还存在于当前关系中就行。4.2 NOT IN 遇到 NULL查询结果突然变成空表现象写“查没选某课的学生”的SQL用了NOT IN子查询本地测试时表里恰好有NULL学号结果查询返回0行怎么查都是空。原因SQL的三值逻辑。当NOT IN子查询的结果集中存在NULL时外层判断“列不等于子查询结果中的任意值”会与NULL比较而NULL既不等于也不不等于任何值最终整体判定为FALSE或UNKNOWN导致所有行都被过滤。解决首选NOT EXISTS写法相关子查询对NULL的处理更符合直觉或者先在子查询里显式过滤掉NULL比如加WHERE Sno IS NOT NULL。以后看到NOT IN条件第一反应就是查子查询列是否绝对非空不确定就换写法这是习题答案里不讲明但考试极爱考的隐含坑。4.3 无损连接判定追踪表算半天下不对现象用追踪表算法验证无损连接时填了几轮数据项后不确定某一行算不算“被填满”最后判断错误。原因追踪表法要求初始化时把每个属性标上符号然后反复扫描函数依赖若某函数依赖左边属性在表中有多行取值相同就把右边符号统一。很多人把“行中所有符号都变成a下标”这个条件理解成“有a就行”导致误判。解决死记最终条件只要最终结果中存在一行全部是a下标如a1, a2, a3...就能判定无损连接。做题时我习惯每扫描完一轮函数依赖就在行末画一条竖线标记这一轮的快照防止自己混轮。计算量大的题目就列出符号矩阵逐行写不要心算心算必错。4.4 拿答案对结论却不动手推导考试换个问法就慌现象平时复习时觉得课后题都“看懂”了因为参考答案一步步都读得明白但到了模拟考试遇到同考点的新题完全想不起解法入口。原因只读答案进入了“被动理解”模式大脑会把参考答案当成已知信息不需要调动主动推理。真正考试没有现成答案缺少推导路径的肌肉记忆时就断片。解决每道题必须闭卷重做然后把自己写的答案与参考解答逐行对比。对比时不只看结果还要看第一步切入点是否一致。如果第一步就不一样说明你的解法路径与标准方法脱轨要立刻纠偏并复述一遍解题入口是什么。我复习时把“能否不看答案复现完整推导”作为一道题算不算掌握的唯一标准。4.5 把标准答案当唯一解遇到多解题目死板抄写现象范式分解题参考答案给出一种分解结果自己也照抄但考试时题目要求稍作变化自己就再也写不出第二种分解。原因3NF分解本来就可能存在多种结果无损连接和保持依赖的约束下分解路径不唯一。习题答案只展示一种但不代表其他合法分解错误。解决做范式分解题时每次做完都追问一句“还有没有别的切分方式”。我常用反向验证法把自己拆出来的关系拿去逐条检查函数依赖是否完整保留、能否无损连接只要两条都满足就承认它是合法解。这样既不容易被标准答案框住考试时也能更灵活。5. 把答案变成复习资产自测、错题与考点映射的进阶用法5.1 按考点频率分配复习资源而不是按章节平均使力习题答案统计出来之后你可以把每道错题的考点汇总成一张表统计每个考点出现的次数。例如最近一次复习中“候选键求解”错了3次“SQL分组过滤”错了2次“两段锁协议”错了1次。那么下一次复习时间就应该优先投入候选键求解而不是从头翻第一章重看。这张表就是你的个人考试地图比目录更真实。考点错题次数涉及题目类型下次复习优先级候选键求解3范式推导高SQL分组过滤2SQL查询高无损连接验证1范式推导中关系代数操作顺序1关系代数中复习节奏上我习惯按1天、3天、7天的间隔重做错题。第一天重做一遍并对照答案第三天只看题目不看答案写出完整解法第七天再做一次这次要求完全闭卷且复现推导过程。三次都能顺畅完成才算真正消化。5.2 反向出题是最快的验证方式这本题答案用到最后最高级的技巧是反向出题。把一道“求候选键”的题改成“判断该关系属于第几范式”把一道“用NOT EXISTS改写了”的题改回“用连接实现”再来一遍。反向出题猛戳知识点的可迁移能力因为你要站在出题人的角度重新组织条件这个视角比做题本身更能暴露理解漏洞。我当年复习到最后阶段每做错一道题就花十分钟给这道题改一个同类型的变体比如换一个表名、换一个连接条件、换一个查询条件。能顺利解出变体才说明原理通了。任何一道题只懂了原题、变体就卡壳说明你记住的是题目而不是方法。希望这篇梳理能帮你把习题答案用出真正的效果——不是对答案而是校准思维。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?
咨询建站