简介:数据库是信息时代组织和存储数据的核心工具,掌握其基础概念对初学者尤为关键。《数据库系统原理及应用教程第五版》习题答案完整版已打包上传,覆盖教材各章节核心概念与课后习题解答,按章节整理、以问答形式呈现,每个问题均给出条理清晰的参考答案和答题思路。资源为单个 docx 文档,资源包大小约 814KB,内容从数据、数据处理与数据管理的定义和目标,到数据库及数据库管理系统(DBMS)功能、数据冗余危害、数据的整体性与共享性、文件系统管理缺陷、数据库系统阶段特点与硬件要求,再到数据库系统软件组成、数据库管理员职责、三级模式结构和数据独立性等重难点均有详细解析,适合复习、自测与教学参考。目前已有 4894 人学习下载,读者可对照教材章节查阅答案,快速定位薄弱知识点,掌握数据库基础体系与答题要点。
1. 数据库系统原理及应用教程第五版习题答案:先别急着背,先想清楚它该帮你干什么
很多人拿到《数据库系统原理及应用教程第五版》的习题答案后,第一反应是把简答题背下来,把SQL题的答案抄一遍,觉得这样就算复习完了。结果一到考试,题目稍微换个条件,函数依赖一变,照样不会。原因不是题刷得少,而是把答案当成了终点,而不是对照物。这套习题答案的真正用途,是帮你建立“自己先做→再核对→追溯解析”的闭环;尤其是关系代数、范式分解和事务并发这几块,答案里的每一步推导都值得拆开看。它适合正在备考期末、准备复试,或者想通过刷题把关系模型彻底理清的从业者。用好了,它是教材的延伸;用错了,它只是心理安慰。
2. 把第五版的习题体系拆开看:考点权重与章节地图,重点该刷哪几章
2.1 先建知识地图,别让答案牵着鼻子走
拿到答案后,我建议先不要翻任何一道题,而是把教程的目录通读一遍,再按知识类型把章节分成四个板块:基础概念、关系模型与SQL、数据库设计、数据库系统实现。这样做的原因是:习题答案里不同板块的可用度完全不同。基础概念的题,答案是唯一且稳定的,背下来就行;关系代数和SQL的题,答案往往只给最终结果,需要你自己补推导;范式的题,答案存在版本差异,需要回到教材定义去核对。如果你从第一页开始顺序刷,很可能在“数据库系统概述”这种概念章节花掉大量时间,后面SQL和范式却没时间练,这是最常见的复习失控。
我的做法是把每个章节的题号、题型、预计耗时、答案是否带解析记在一张表里,可以用笔记软件,也可以手写。比如概念章节的题只标“背”,关系代数的题标“手推”,SQL的题标“上机验证”。画完这张表,你就会清楚看到:SQL和关系模型相关的题目通常会占据总题量的一半以上,范式和事务的题虽然数量不多,但每道题需要的时间多,答案也更容易踩坑。后面复习时,这张表就是你每天分配时间的依据。
这里有一个容易被忽略的动作:把答案里“略”和“见教材Pxx”这类题目单独挑出来。它们并不是不重要,往往因为作者觉得太基础或太难,不适合写进答案。练习题遇到这种题,我会先看教材正文有没有对应例题,如果有就直接复现一遍,没有就和同学讨论。这套教程第五版里的题目,基本都属于需要动手演算才能得分的类型,跳过意味着考试时容易空手。
2.2 关系模型与SQL章节:题量最大且分值最稳,先重兵攻略
关系模型是整本教程的骨架,习题答案里评分最严格的部分也在这里。常见的题型有:给两个关系写关系代数表达式;给中文需求写SQL;给定SQL让你说明查询结果。关系代数和SQL的答案风格不太一样:关系代数答案通常只有一行符号,但手写过程必须一步一步展开;SQL答案虽然能直接运行,但不代表逻辑正确,因为同样的查询可以用多种方式表达。
我刷这几章用的是“三遍法”。第一遍,把答案盖住,只看题干,在草稿纸上写下自己的关系代数表达式或SQL,写不下去再揭答案,看懂后放下笔,把解析默念一遍。第二遍,合上答案,重新写,直到结果和答案一致。第三遍,把题目的条件换掉,比如把“查询成绩大于80的学生”改成“查询成绩在80到90之间的学生选课情况”,逼迫自己用同一个模板解决变体。三遍法最费时间的是第一遍,因为你的错误会暴露出来,比如把连接条件写反,或忘了用聚合函数。
这一章里,答案最常见的“隐藏依赖”是自然连接与等值连接的区别。很多教材在关系代数章节默认使用自然连接,也就是连接后只保留一个同名列,而SQL里JOIN ON等价于等值连接,会保留两个同名列。当你对照答案发现结果多了一列时,先确认答案用的连接类型,再确认题目要求的是不是自然连接。尤其在做课后习题时,第五版教程关系代数部分大量使用自然连接记法,直接迁移到SQL会踩坑,这点务必留意。
2.3 范式与函数依赖:答案最容易“打架”的一章,反倒最该慢刷
范式章节是备考分水岭。同样是判断一个关系最高属于第几范式,不同教材因为“候选键”和“部分依赖”的定义稍不同,结论可能差一档。这道题的答案在网传的版本里经常互相矛盾,连带着读者也怀疑自己。我在用这套习题答案时,会把所有范式题集中到一起,先不看答案,自己给每道题写三条笔记:候选键是谁,主属性有哪些,函数依赖集是否尽量小。写完再对照答案,只要这三条一致,结论一般差不了。
判断范式有一个固定流程,我反复用:先求候选键,用闭包验证;再看是否存在非主属性对候选键的部分依赖,有则不满足2NF;再看是否存在非主属性对候选键的传递依赖,有则不满足3NF;最后看每个函数依赖的决定因素是不是候选键,不全满足则不为BCNF。这里最难的是求闭包,很多人求到一半就漏掉依赖。我建议每求一步,就检查依赖右边有没有新属性可加入,直到闭包不再变化。
当你发现自己的结论和答案不一致时,别急着改,先把两边的函数依赖集合列出来,逐条比对。常见分歧是答案里把“AB→C, C→E”合并成“AB→E”,虽然这个依赖可以通过传递得到,但如果你在判断时把它当原始依赖,就可能导致出现传递依赖的误判;实际上传递依赖本来就该基于推导出的依赖判断,所以这个合并是允许的。另一个常见分歧是在无损分解的验证上,答案只说“分解保持函数依赖”,没提“无损连接”,这时你要自己用自然连接验证,别默认分解正确。
2.4 用答案做每日复盘:按考点打钩,而不是按题号打钩
刷完一部分题后,我习惯在答案上按考点做标记,而不是只打对错。比如一道SQL题,考点可能是“分组排序”,我会在题号边上写“GROUP BY+HAVING”。这样第二轮复习时,只需要看考点标签,不用重新读题。每晚睡前,我会抽查五个考点标签,让自己不看答案说出对应的解题步骤;说不出来的,第二天重新做一遍相关题。这个方法看着笨,但能有效防止“翻开书全认识,合上书全忘记”。
答案中那些“强调一定不要用子查询”的提示,不要全信。它通常是为了让你练习连接写法,并不代表真实业务里子查询不能用。你要做的是把多种写法都跑一遍,对比执行计划或者结果,久而久之自然知道什么时候用JOIN更好、什么时候用EXISTS更稳。这个过程里,答案只是一个引子,真正让你成长的是自己动手验证的那几步。
3. 用答案核对过的典型题型:关系代数和SQL的解题模板与验证方法
3.1 关系代数表达式:把中文题干翻译成四步操作
很多初学者看到关系代数就头皮发麻,符号不认识,表达式也看不懂。其实关系代数的复杂度来自题目给你的关系数量和操作词的隐藏。拿到题干,我一般先找四个要素:投影列、选择条件、连接表、特殊动词。投影列对应“查询/显示/输出”后面的字段;选择条件对应“WHERE/满足/大于/等于”这类词;连接表对应题干中出现了两个以上实体;特殊动词对应“全部、所有、至少、不存在”这些词,它们决定要不要用除法或差集。
举个例子。有两个关系:学生(学号,姓名,系别)和选课(学号,课程号,成绩)。查询“信息系中选修了课程号C1且成绩大于85的学生姓名”。我先做连接:学生和选课按学号连接,得到临时关系,包含所有字段。再做选择:系别=‘信息系’,课程号=‘C1’,成绩>85。最后投影:姓名。写出来是:
π_姓名(σ_系别='信息系' ∧ 课程号='C1' ∧ 成绩>85 (学生 ⋈ 选课))有的答案会写成先选择后连接,比如先在学生表里筛出信息系,再在选课表里筛出C1和成绩,最后连接。这样写也对,而且执行顺序更清晰。关键是要看答案有没有省略括号或表名,补齐后再判断逻辑是否一致。如果答案只给了最终表达式,我会在草稿纸上把中间关系表写出来,比如连接后先有学号、姓名、系别、课程号、成绩五列,经过选择和投影后剩下一列姓名,这样推导过程就完整了。
“全部”型题目是另一个高频坑。查询“选修了所有课程的学生”,关系代数标准写法是用除法:学生−选课÷课程,或者π_学号(选课÷课程)。但教材版本和网传答案对除法符号的定义有出入,有的用÷,有的用⊘,还有的干脆不提及。为了避免考试被符号卡住,我用的是差集等价写法:先求“至少有一门课程没选的学生”,再用全体学生减去它。具体步骤是:π_学号(学生) − π_学号(选课 ⋉ (π_课程号(课程) − π_课程号(选课)))。这个写法虽然长,但不会因为符号歧义丢分,而且在考试推导时更容易解释每一步的意图。
3.2 SQL查询:先写逻辑骨架,再补语法细节
SQL题在第五版习题答案里数量最多,而且很多答案只给一句最终SQL,没有过程。我自己写SQL时,会按这样的顺序推:先确定要查哪张表,写FROM;再确定要过滤哪行,写WHERE;然后看是否需要对行分组,写GROUP BY;分组后是否还要过滤,写HAVING;最后确定输出顺序和格式,写ORDER BY。这个顺序不是书写的顺序,而是脑内建模的顺序,照着它能减少漏条件。
以一个常见题为例:选课表中保存每名学生选修的每门课程及成绩,查询平均成绩不低于80分的课程编号和平均成绩,结果按平均成绩降序。
SELECT cid, AVG(score) AS avg_score FROM SC GROUP BY cid HAVING AVG(score) >= 80 ORDER BY avg_score DESC;这里的逻辑说明:cid是分组列,可以出现在SELECT中;AVG(score)是聚合结果,必须配GROUP BY使用。WHERE和HAVING的区别是这道题最容易出错的地方:如果把条件写在WHERE score>=80里面,查询会先丢掉所有低于80的分数,再计算平均分,结果会偏离题意;只有用HAVING过滤分组结果,才符合“平均成绩不低于80”。答案里如果出现这种顺序错误,执行结果能直观暴露问题,所以这道题非常适合上机验证。
另一个经典题型是“找出选修了全部课程的学生”,标准答案常用NOT EXISTS双重否定。这个结构在教材里出现过很多次,但换表名后很多人写不出来。
SELECT sname FROM Student AS s WHERE NOT EXISTS ( SELECT 1 FROM Course AS c WHERE NOT EXISTS ( SELECT 1 FROM SC WHERE SC.sid = s.sid AND SC.cid = c.cid ) );逻辑说明:最内层判断某个学生s是否选了课程c;第二层NOT EXISTS判断是否存在一门课程c,使得这个学生没选它;最外层NOT EXISTS判断是否存在这样的课程。只有当“没有一门课程没选”时,学生才被选中。这个结构如果第一次见,建议逐步拆开看:先只看内层,手动指定学生S1和课程C1,看是否返回行;再扩大到所有课程;最后理解双向否定。
参数说明:这段代码使用了表别名s和c,分别对应Student和Course。别名在MySQL中可以省略AS,但在标准SQL建议保留,这样在子查询或JOIN中引用限定列名时可读性更高。另外NOT EXISTS子查询里SELECT 1是习惯写法,因为只关心是否存在行,不关心列值;换成SELECT *也能跑,但SELECT 1能少读一些列信息,逻辑上更干净。
3.3 用实际数据库跑一遍:把答案变成可执行、可验证的脚本
习题答案里的SQL有时候会和实际数据库方言冲突,比如老教材里写“SELECT * FROM A, B WHERE A.id = B.id”,在MySQL 8.0仍能跑通,但新版标准SQL里推荐显式JOIN。不只是语法,答案可能省略空值处理,也可能因为建表语句缺失而在某些数据库报错。这时最有效的核对手段是把题目的表结构和样例数据复制到本地数据库,让数据库自己回答。
下面是一个最小验证例子,使用SQLite。先建表并插入数据,再执行上面那道“全部选课”的查询。
CREATE TABLE Student (sid TEXT PRIMARY KEY, sname TEXT); CREATE TABLE Course (cid TEXT PRIMARY KEY); CREATE TABLE SC ( sid TEXT, cid TEXT, score REAL, PRIMARY KEY (sid, cid) ); INSERT INTO Student VALUES ('S1', 'A同学'), ('S2', 'B同学'); INSERT INTO Course VALUES ('C1'), ('C2'), ('C3'); INSERT INTO SC VALUES ('S1', 'C1', 90), ('S1', 'C2', 85), ('S1', 'C3', 92); SELECT sname FROM Student AS s WHERE NOT EXISTS ( SELECT 1 FROM Course AS c WHERE NOT EXISTS ( SELECT 1 FROM SC WHERE SC.sid = s.sid AND SC.cid = c.cid ) );执行结果只会返回A同学,因为B同学没有选修任何课程。这里参数说明:SQLite的TEXT类型对应字符串,PRIMARY KEY定义在列上可以省略NOT NULL。插入语句中多行VALUES是SQLite支持的写法,其他数据库如PostgreSQL也支持。使用SQLite是为了免安装,如果你手头有MySQL或MariaDB,执行效果一样,只是建表时可能需要显式指定字符集。
核对答案时,我常常遇到三种结果:第一种,答案SQL跑通且结果符合预期,这属于正常;第二种,答案SQL跑通但结果和答案手算的不一致,这多半是样例数据不一致或空值导致,可以把数据换成题目给的原始样例再跑;第三种,答案SQL报错,这多半是语法方言问题,比如某些数据库要求别名不加AS,或者不允许在HAVING里用别名。无论是哪种,把答案调整到能跑的过程本身就是在学数据库,盲目背不会遇到这些问题。另外,如果答案里用了ORDER BY一个不在SELECT里的列,在很多数据库里会报错或产生不可预期排序,这也是一个常见的答案“假阴性”来源。
4. 范式、事务与并发控制:答案不符时,到底该信答案还是信书上定义
4.1 范式判断的标准流程:先把候选键和依赖写清楚
范式的答案只给一个结论,但考试要求你写出推导过程。所以我把范式题当成“计算题”,每次都在草稿纸上按标准流程走一遍,而不是直接看答案。先看一个完整例子。设有关系R(A,B,C,D),函数依赖集合F={AB→C, C→D, D→A},要判断R最高满足第几范式。
第一步,求候选键。先求AB的闭包:由AB→C得到AB扩展为ABC,由C→D得到ABCD,由D→A得到ABCD,所以闭包是ABCD,AB能决定所有属性,AB是候选键。再看A单独,闭包只有A;B单独只有B,所以AB是唯一候选键。
第二步,确定主属性为A和B,非主属性为C和D。第三步,检查2NF:是否存在非主属性对候选键的部分函数依赖?C依赖AB(完整依赖,不是只依赖A或B),D依赖C再依赖AB,D并不直接依赖候选键的一部分,所以没有部分依赖,满足2NF。第四步,检查3NF:AB→C,C→D,这里C不是候选键,且D不是主属性,因此D通过C传递依赖于AB,不满足3NF。结论:最高是2NF。
如果答案写3NF,你需要检查它的函数依赖集合是否多了“C→A”之类的冗余。在求依赖闭包时,有些依赖可以由其他依赖推导出来,比如D→A和AB→C可能推出AB→D,但是否影响范式判断,取决于原始集合。严格的做法是先把F写成最小函数依赖集,再进行范式判定,这样不会因为冗余依赖而误判。练习的时候,我习惯用表格记录每一步:关系、候选键、主属性、非主属性、是否存在部分依赖、是否存在传递依赖、判定结果。这张表可以帮你快速定位和答案的分歧点。
无损分解的验证是另一个失分点。如果题目要求把R分解为R1(A,B,C)和R2(C,D),判断这个分解是否无损。做法是看R1∩R2是否等于R2的关键字?准确说,要满足R1∩R2能决定R1中其他属性,或能决定R2中其他属性。这里R1∩R2是C,C→D,所以C能决定R2的属性D,因此是无损分解。但R1∩R2不能决定A或B,所以从R2的角度不满足,但无损分解只需要一个方向的包含关系成立。习题答案里经常只说“满足依赖保持”而不验证无损,你要自己算,别默认答案正确。
4.2 事务ACID与隔离级别:别让“标准答案”限制了你
事务部分的简答题,答案背起来很容易,但很容易答成“三字经”。比如“什么是脏读?”“什么是不可重复读?”“什么是幻读?”这类题,只看答案没问题,但考试会换一种问法:给你一个并发调度,让你指出哪个现象会出现在哪种隔离级别下。这时候只会背概念就不够用了。
我的方法是画一张表,把四个隔离级别和三个异常现象的对应关系先自己填一遍,再对照教材和答案。表如下:
| 隔离级别 | 脏读 | 不可重复读 | 幻读 |
|---|---|---|---|
| 读未提交 | 可能 | 可能 | 可能 |
| 读已提交 | 不可能 | 可能 | 可能 |
| 可重复读 | 不可能 | 不可能 | 取决于实现 |
| 可串行化 | 不可能 | 不可能 | 不可能 |
这张表在第五版教材里很可能作为定义给出,但答案里可能没有这么完整,需要你自己补全。注意“可重复读”那一行的“取决于实现”是关键:按SQL标准定义,可重复读不隔离幻读;但MySQL InnoDB默认的可重复读配合间隙锁,可以阻止部分幻读。这也是习题答案和实际数据库行为出现冲突的常见原因。
当你发现“可重复读是否避免幻读”这个格子填了“可能”,而习题答案直接写“不可避免”时,不要慌。先用教材前文的定义来判断:如果教材是按SQL标准讲的,可重复读确实不避免幻读;如果教材按某个具体数据库实现讲,比如MySQL InnoDB默认的REPEATABLE READ配上间隙锁,可能避免部分幻读。答案本身没有唯一性,关键看它的上下文。这种情况我会直接在答案旁边标注“依DBMS实现而定”,并记录教材依据段落,复习时不容易第二次纠结。
为了加深理解,可以真的在MySQL里做一次实验:开两个会话,一个事务先查询一个不存在的范围,另一个事务插入该范围内的记录,然后第一个事务用普通SELECT和SELECT ... FOR UPDATE分别再查,观察是否有幻行。实验结果比答案的表述更能建立长期记忆。做这类实验要记得事务结束后提交或回滚,否则会长时间占用锁,影响其他会话。如果实验环境是MySQL 8.0,注意默认的隔离级别就是REPEATABLE READ,和课本描述未必完全一致。
4.3 冲突可串行化:用优先图画调度,比背答案更稳
并发控制题目中,判断一个调度是否冲突可串行化的标准方法就是画优先图。很多同学觉得这个考点抽象,干脆背答案。我的做法是固定画图流程,三分钟出结果。先把调度中的所有操作按时间顺序列出来,标注事务编号和数据项;再找出冲突对:两个事务访问同一个数据项,且至少有一个是写操作;然后按先后顺序画有向边;最后检查图中是否有环。
看一个具体调度:T1读(A),T2写(A),T1读(B),T2写(B)。冲突对有两对:T1读A和T2写A冲突,且T1先于T2,所以画边T1→T2;T1读B和T2写B冲突,且T1先于T2,再画边T1→T2。图中没有环,因此该调度等价于串行调度T1→T2,是冲突可串行化的。这个例子里,两个冲突对的先后顺序一致,所以没环;如果存在一个调度中,T1先写A,T2后读A,同时T2先写B,T1后读B,那画出来的边就是T1→T2和T2→T1,构成环,该调度就不可串行化。
习题答案往往会直接给出“等价于串行调度”,但没有画出边。为了检验答案,我会自己画图。这里有个容易踩的坑:如果两个操作都是读,不算冲突,不要画边;如果两个操作涉及的数据项不同,也不算冲突;如果两个操作是同一个事务,更不算冲突。画完图后,如果答案说有环,而你没找到环,再检查是否漏掉了某两个事务之间通过第三个事务间接形成的环。优先图只画直接冲突边,但环的存在可以是多事务构成的,比如T1→T2、T2→T3、T3→T1,需要找完整路径。
有些题目还会问“该调度是否可恢复”或“是否避免级联回滚”,这和冲突可串行化是两回事。可恢复调度要求:如果T1读了T2写的数据,那么T1必须在T2提交之后提交;避免级联回滚要求:事务只能读已提交事务的数据。习题答案里这两个概念经常被混在一起说,但考试会分开考。我在刷题时会把“冲突可串行化”“可恢复”“避免级联回滚”三个判定标准写在同一张卡片上,避免混淆。如果你发现答案把两个概念混为一谈,一定先回教材看定义,别接受一个模棱两可的表述。
5. 刷这套习题答案的避坑指南:五种常见的翻车现场与排查建议
答案在使用过程中翻车不一定是答案本身错了,更可能是学习方法或环境差异导致的。下面这五类问题,是我刷题和辅导同学时最常见的,每条都按现象、原因、解决三条来写,你可以直接对照自己的情况。
5.1 现象一:答案里的SQL跑不出预期结果,开始怀疑数据库装错了
我见过不少初学者,照书上的答案输入SQL,运行报错,第一反应是“我数据库是不是装坏了”。其实数据库报错往往是因为答案里的语法和你使用的数据库方言不一致,或者表名、字段名在答案中被省略了。比如教材用的是旧版SQL Server语法,而你在MySQL 8.0里测试,写“SELECT * FROM a, b WHERE a.id=b.id”虽然能跑,但换成“SELECT * FROM a JOIN b USING(id)”又不一样。另一种情况是字段名在两张表里都出现,没加别名前缀,报了ambiguous column错误。
排查顺序是:先看数据库版本和教材所用数据库是否一致,中文教材在SQL章节通常基于某个具体的数据库,有时是Access,有时是MySQL,语法差异很大;再看字段名和表名是否差一个空格或大小写,MySQL在Windows下不区分大小写,Linux下区分;最后把条件拆开执行,先不写WHERE,看能不能查出数据,再逐步加条件。加条件的办法最能定位问题,因为SQL是复合的,任何一个子句错都会导致整体失败。
解决:不要只盯着错误提示,把每个子句单独跑一遍。比如先执行SELECT * FROM SC,确认有数据;再执行SELECT * FROM SC WHERE sid='S1',确认条件没问题。这样能快速把问题缩小到某个子句。如果你在核对答案时遇到这种情况,恭喜你,这其实是一次送上门来的排错练习,远远比背下答案更有价值。把报错信息和最终修正后的SQL记在笔记里,下次再遇到类似报错就能秒懂。
5.2 现象二:范式答案跟书上定义对不上,怀疑自己瞎了
现象很常见:自己判断某关系满足3NF,答案写2NF,或者反过来。于是反复翻书,翻几次更乱了。这通常不是视觉问题,而是判断流程里存在两个隐藏差异。第一个差异是“传递依赖”的判定标准,有些教材把AB→C,C→D这种定义为传递依赖,有些则要求C必须是单属性且C不包含主键;第二个差异是候选键是否唯一,如果候选键有多个,有些教材的“非主属性”定义会变化,结论自然不同。
解决:把题目里的函数依赖集合重新写成最小依赖集,再去掉冗余依赖,然后按标准流程走一遍,每一步都写下依据,比如“因为C不是候选键,D是非主属性,所以存在传递依赖”。如果答案和你一致,你要能说出理由;如果不一致,就把你的推导过程贴给同学或老师看,让别人帮你找岔。很多时候是你在求闭包时漏看了一个依赖,比如右手边有多个属性时,只扩展了其中一个。
最关键的是,不要因为答案和网上某个贴子一致,就认定教材错了。在范式这块,教材定义就是考试标准,第五版习题答案应该符合该教程正文,所以先对照正文,再对照其他资料。如果答案和正文矛盾,那大概率是答案的印刷或整理错误,这时可以遵照正文,并在笔记里标注“此题以正文为准”。
5.3 现象三:背了答案,考试时换了个表名就不会写
这个现象在SQL题里特别典型。学生选课刷到滚瓜烂熟,换成员工部门、订单商品就看不懂了。原因在于背的是具体表名和业务词,不是背结构。数据库查询的本质是:表之间的关联方式和查询条件是模板,业务词只是变量。多对多关系里的“全部”用NOT EXISTS,一对多关系里的“每个”用GROUP BY,这些模板一旦抽离表名,就能复用到任何场景。
解决:在每次刷完一道题后,把题干中的“学生”“课程”“成绩”替换成“员工”“部门”“薪资”,重新写一遍SQL,看模板是否成立。更进一步,把题目抽象成“实体A参与关系R,关系R带属性X,查询条件Y,目标输出Z”,用这个模板去套新题。我一般会专门整理一份“题型模板卡”,每张卡只写结构和伪代码,不写具体表名。比如“找出全部选修了某集合中每个元素的主体”,模板就是“主表A WHERE NOT EXISTS(子表B WHERE NOT EXISTS(关系表R))”。考试时套模板,不会因为换业务词而卡壳。
5.4 现象四:只知道答案,不知道推导,面试一问细节就翻车
面试或复试里,老师不会问你答案是什么,而是问你为什么。比如“这个查询为什么用EXISTS不用IN”“为什么索引能提高查询性能”“为什么可重复读下还会发生幻读”。如果你只背过“答案:可重复读不能避免幻读”,说不清背后机制,就会显得很没底气。习题答案只给结论,不给原因,这是它的属性,不是它的错。错在使用者把结论当成了全部。
解决:每个结论都要补一个“为什么”。我刷题时会在答案旁边写下“如果……”的变形,比如答案用了IN,我会想:如果换成EXISTS,结果相同吗?性能会怎样?答案说“可重复读不避免幻读”,我会追问:MySQL默认隔离级别为什么能避免?间隙锁是怎么工作的?这些问题教材正文不一定讲透,但习题答案是个引子。带着问题去看正文、查资料,比死记硬背更有效。复习到最后,你应该能对每个答案说出至少一条支撑理由,这样才算把题吃透了。
5.5 现象五:号称完整版,于是全程抄,抄完大脑一片空
第五版习题答案被称为完整版,意味着每个题都有结果,但也意味着更容易让人不思考。有些同学刷这种题,习惯直接看答案,看完觉得自己会了,关书后发现根本写不出来。这是最典型的“虚假掌握”。答案再完整,也只是反射检查镜,不是输入键盘。
解决:给自己定一个硬规矩:答案必须先放在一边,先做完题再对答案。如果一道题完全没思路,允许看答案的第一步,然后合上,自己完成剩余步骤;如果看着答案才能写出来,那就把这道题标记为“需要重做”,第二天再独立做一遍。平时练习多花这一倍的力气,考试时能少很多翻车风险。对我自己而言,把“对答案”改成“审答案”,逼着我去质疑它,学习效率反而成倍提升。完整的答案资料本身是工具,别让它把你变成只会抄写的搬运工。
6. 从做题到出题:用答案反向梳理知识点,做到真正吃透
当习题已经刷过两遍,答案都记住了,还想继续深入,我有一个建议:别再做过去的题,试着用答案反推题目,自己出题给自己做。具体有三种玩法。
第一种是“改条件出题”。把答案里的SQL改一个条件,看结果怎么变。比如答案查“成绩大于80”,你就改成“成绩小于60”,看看查询是否变成相反的语义;再改成“成绩大于80或成绩为NULL”,测试自己对空值的理解。关系代数也一样,把连接条件从等于改成不等于,让表达式自己推导一遍,过程中你会发现很多教材上讲过的边角知识。
第二种是“改难度出题”。把答案里的简答题改成选择题,把计算题改成判断对错的题,或者反过来把选择题改造成简答题。比如答案说“可重复读可以防止不可重复读”,你就把它改成四个选项的单选题,故意把“可以防止幻读”也放进去当干扰项,再自己解释为什么不对。这个过程等于把一个结论拆成了多个知识点,记忆会牢固很多。
第三种是“用答案做测试集”。把每章的答案收集起来,当成验收标准。自己出十道题,覆盖关系代数、SQL、范式、事务隔离级别、并发调度五大块,做完后和答案比对,每对上一个就在错题本上打一个钩。如果十道题全对,说明这章基本过关;如果还有三道不会,就回去重刷对应模板。
最后说一个我自己的教训。当年备考时,我也曾图快直接背答案,结果期末试卷里有一道“给出函数依赖,判断无损分解”的题,我明明见过原题,却写不出验证过程,白白丢了分。从那以后,我给自己定了一条规矩:任何答案,必须能独立推导一遍才算数。这条规矩很笨,但很管用。完整版答案不是捷径,它只是让你在这条路上少走弯路的参照物。希望帮到你。
本文还有配套的精品资源,点击获取