ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

数据库原理及技术(钱学忠)答案:从背答案到真懂原理的落地路径

2026/9/25 16:34:28 拓冰建站 浏览量
数据库原理及技术(钱学忠)答案:从背答案到真懂原理的落地路径 简介这份资源是钱学忠《数据库原理及技术》教材的配套习题答案面向高校数据库课程学生、备考人员及需要巩固理论的自学者帮助解决课后练习与知识点理解中的疑难。内容围绕数据库设计、SQL语言、关系数据库理论、DBMS与数据库管理等核心章节展开可对照教材逐章核对答案、梳理E-R模型转换、关系代数演算及规范化设计等关键思路。资源以rar压缩包形式提供整体约16.69MB上游未提供具体文件数量与类型明细下载后可按章节结构查阅。目前已有693人学习下载适合作为课程复习与习题演练的参考。通过对照答案与教材推导过程读者能加深对关系模型、事务控制、备份恢复与性能调优等概念的理解提升独立完成数据库设计与查询优化的能力。1. 数据库原理及技术钱学忠答案从背答案到真懂原理的落地路径很多人搜「数据库原理及技术钱学忠答案」其实不是想抄答案而是被范式分解、SQL 嵌套、事务隔离这几类题卡住了想找个能对照验证的参照系。我当年带数据库助教时也走过弯路把答案背得滚瓜烂熟一到上机建表就翻车连 3NF 分解都能拆出数据丢失。后来才明白答案只是结果真正值钱的是推导过程能不能复现。这篇笔记就按一线工程师的路子把「钱学忠」这套教材里最常考的几块——关系代数、范式分解、SQL 查询、事务与并发——拆成能自己动手验证的步骤。适合正在备考、做课设或者想借这套题把数据库底层逻辑重新捋一遍的人。你不需要先有答案跟着走一遍答案自己就出来了。2. 关系模型与范式分解把「答案」还原成可推导的步骤2.1 先搞清楚这套题到底在考什么「数据库原理及技术钱学忠」这类教材的习题核心就四块关系代数与关系演算、函数依赖与范式分解、SQL 的 DDL/DML/DCL、事务与并发控制。搜答案的人八成卡在前两块因为它们是纯逻辑推导没有 SQL 那种「跑一下就知道对错」的即时反馈。我一般建议先把函数依赖的闭包算法吃透这是后面所有范式判断的地基。闭包怎么算给定属性集 X 和函数依赖集 F求 X 能推出的所有属性。手算容易漏写个脚本验证最稳。下面这段 Python 就是最小可用的闭包计算器直接抄就能跑。# 函数依赖闭包计算输入属性集和依赖列表输出闭包 def closure(attrs, fds): result set(attrs) changed True while changed: changed False for lhs, rhs in fds: # 若依赖左边被当前结果包含则把右边并入 if set(lhs).issubset(result) and not set(rhs).issubset(result): result | set(rhs) changed True return result # 例R(A,B,C,D)F {A-B, B-C, A-D} fds [(A, B), (B, C), (A, D)] print(closure(A, fds)) # 输出 {A,B,C,D}说明 A 是候选码逻辑说明外层while changed保证依赖链能传递下去比如 A→B、B→C 要迭代两轮才能把 C 推出来。参数说明attrs传字符串或列表都行fds是(左边, 右边)的列表左边右边都用字符串表示属性。跑出来{A,B,C,D}就说明 A 能决定全表A 是候选码。这一步做对了后面判断 2NF、3NF 才有依据。2.2 范式分解从 1NF 到 3NF 的判断与拆解范式判断的口诀很多人背过但一到具体题就懵。我的做法是固定三步先找候选码再看非主属性对码的部分依赖和传递依赖最后决定拆不拆。1NF 要求属性原子性这个现代数据库基本默认满足2NF 消除非主属性对码的部分依赖3NF 再消除传递依赖。举个教材里高频的例子R(学号, 课程号, 姓名, 成绩, 系名, 系主任)函数依赖是 (学号,课程号)→成绩学号→姓名学号→系名系名→系主任。候选码是 (学号,课程号)。成绩完全依赖码没问题但姓名、系名只依赖学号这是部分依赖所以不满足 2NF。拆法是把只依赖学号的部分单独成表学生表(学号,姓名,系名)系表(系名,系主任)选课表(学号,课程号,成绩)。拆完再检查系表里系名→系主任系主任不传递依赖别的满足 3NF。这里有个血泪经验拆表不是越细越好。我见过有人把成绩也单独拆出去结果查询要三表连接性能反而下降。范式分解的目标是消除冗余和更新异常不是追求形式上的最高范式。实际工程里经常故意保留 2NF 甚至反范式就是为了查询效率。做题时按教材要求拆到 3NF但心里要清楚这是理论最优不是工程最优。2.3 用 SQL 反向验证分解是否正确拆完表别急着交卷用 SQL 建出来跑一遍看能不能无损连接回原表。这是我最推荐的验证方式比对着答案看靠谱得多。-- 按 3NF 分解建表 CREATE TABLE student ( sno VARCHAR(10) PRIMARY KEY, sname VARCHAR(20), dept VARCHAR(20) ); CREATE TABLE dept ( dept VARCHAR(20) PRIMARY KEY, dean VARCHAR(20) ); CREATE TABLE sc ( sno VARCHAR(10), cno VARCHAR(10), grade INT, PRIMARY KEY (sno, cno) ); -- 无损连接验证连接后应能还原原始信息 SELECT s.sno, s.sname, s.dept, d.dean, sc.cno, sc.grade FROM student s JOIN dept d ON s.dept d.dept JOIN sc ON s.sno sc.sno;逻辑说明三表通过 sno 和 dept 连接如果能查出完整的学号、姓名、系名、系主任、课程、成绩说明分解是无损的。参数说明主键设置很关键student 用 sno 做主键dept 用 dept 做主键sc 用联合主键这样才符合分解后的依赖关系。如果连接后出现重复行或丢失行说明分解有问题得回头检查依赖集。3. SQL 查询与关系代数把嵌套题拆成可执行的语句3.1 关系代数转 SQL 的固定映射教材里关系代数和 SQL 是两条线很多人分开学结果遇到「用关系代数表示」和「用 SQL 实现」两种问法就乱。其实它们有固定映射选择 σ 对应 WHERE投影 π 对应 SELECT自然连接 ⋈ 对应 JOIN并 ∪ 对应 UNION。我一般让学生先把关系代数式写出来再逐符号翻译成 SQL基本不会错。比如「查询选修了数据库课程的学生姓名」关系代数写法是 π姓名(σ课程名数据库(学生⋈选课⋈课程))。翻译成 SQL 就是三层先连接三表再过滤课程名最后投影姓名。这个映射练熟之后再复杂的嵌套都能拆。3.2 嵌套查询与 EXISTS 的实战写法教材里最爱考的嵌套题是「查询选修了全部课程的学生」和「查询没选修某课的学生」。前者用双重 NOT EXISTS后者用 NOT IN 或 NOT EXISTS。这两种写法语义有细微差别NOT IN 遇到 NULL 会翻车这是经典坑。-- 查询选修了全部课程的学生双重 NOT EXISTS SELECT sname FROM student s WHERE NOT EXISTS ( SELECT * FROM course c WHERE NOT EXISTS ( SELECT * FROM sc WHERE sc.sno s.sno AND sc.cno c.cno ) ); -- 查询没选修 C01 的学生推荐 NOT EXISTS避免 NULL 陷阱 SELECT sname FROM student s WHERE NOT EXISTS ( SELECT * FROM sc WHERE sc.sno s.sno AND sc.cno C01 );逻辑说明双重 NOT EXISTS 的语义是「不存在一门课该学生没有选修」等价于「选修了全部课程」。参数说明内层sc.sno s.sno是关联条件把外层学生和内层选课记录绑起来。注意 NOT IN 的坑如果子查询返回 NULL整个 NOT IN 结果会是 UNKNOWN查不出任何行。所以涉及可能为空的列时一律用 NOT EXISTS。3.3 聚合与分组GROUP BY 的三个必调点GROUP BY 的题错得最多的是三处SELECT 里出现非聚合列、HAVING 和 WHERE 混用、COUNT() 和 COUNT(列) 搞混。我一般强调WHERE 在分组前过滤行HAVING 在分组后过滤组SELECT 里的非聚合列必须出现在 GROUP BY 里COUNT() 数所有行COUNT(列) 跳过 NULL。-- 查询平均成绩大于 80 的课程号及平均分 SELECT cno, AVG(grade) AS avg_grade FROM sc WHERE grade IS NOT NULL GROUP BY cno HAVING AVG(grade) 80;逻辑说明先用 WHERE 过滤掉成绩为空的行再按课程号分组最后用 HAVING 筛出平均分大于 80 的组。参数说明AVG(grade)自动忽略 NULL但显式加WHERE grade IS NOT NULL更清晰。如果写成HAVING avg_grade 80在某些数据库里会报错因为别名在 HAVING 里不一定可用稳妥写法是重复聚合函数。4. 事务与并发控制答案里最容易忽略的隔离级别4.1 四种隔离级别与三类读异常教材讲事务必考 ACID 和隔离级别。很多人背得出「读未提交、读已提交、可重复读、串行化」但说不清哪个级别解决哪个异常。我整理成一张表做题时直接对照。隔离级别脏读不可重复读幻读读未提交可能可能可能读已提交不可能可能可能可重复读不可能不可能可能串行化不可能不可能不可能这张表要能默写。脏读是读到别人未提交的数据不可重复读是同一事务内两次读同一行结果不同幻读是同一事务内两次范围查询行数不同。MySQL 的 InnoDB 默认是可重复读但通过间隙锁在一定程度上也解决了幻读这是教材和实际实现的差异点考试按教材答工程按实际用。4.2 用两段锁协议分析并发调度教材里的并发调度题给一个调度序列问是否可串行化。判断方法是看是否满足两段锁协议加锁阶段只能加锁不能解锁解锁阶段只能解锁不能加锁。我一般让学生先标出每个事务的加锁点和解锁点如果解锁后又加锁就违反两段锁可能不可串行化。举个典型调度T1 读 AT2 读 AT1 写 AT2 写 A。这个调度如果 T1 和 T2 都先加锁再解锁且解锁后不再加锁就是可串行化的。但如果 T1 解锁 A 之后 T2 才加锁 A中间又插了别的操作就可能出问题。分析时画时间轴最直观横轴时间纵轴事务标出每个操作的先后。4.3 死锁的预防与检测死锁四个条件互斥、占有并等待、不可抢占、循环等待。破坏任意一个就能预防。工程里最常用的是按固定顺序加锁破坏循环等待。教材题里常问「如何预防死锁」答按序加锁、一次性申请所有资源、超时释放都行。检测死锁用等待图事务是节点等待关系是有向边图里有环就是死锁。解除死锁靠回滚代价最小的事务。这块考试一般考概念但实际调数据库时死锁日志是排查性能问题的关键线索我后面会讲怎么看。5. 避坑与排查搜答案时最容易踩的五个坑5.1 现象范式分解后连接查询结果变多原因分解时没保证无损连接或者连接条件写错导致笛卡尔积。解决检查分解是否满足无损连接定理即两个子模式的交集能决定其中一个子模式。用 SQL 跑一遍连接对比行数多了就是连接条件漏了。5.2 现象NOT IN 子查询查不出任何结果原因子查询返回了 NULLNOT IN 遇到 NULL 整个条件变 UNKNOWN。解决改用 NOT EXISTS或者在子查询里加WHERE 列 IS NOT NULL。这是 SQL 里最经典的玄学问题我当年在这上面浪费过一下午。5.3 现象GROUP BY 查询报「不是 GROUP BY 表达式」原因SELECT 里出现了既不在 GROUP BY 里、也不是聚合函数的列。解决要么把该列加进 GROUP BY要么用聚合函数包起来。不同数据库严格程度不同MySQL 旧版本宽松新版本和 PostgreSQL 都严格别依赖宽松模式。5.4 现象事务隔离级别设了可重复读还是有幻读原因可重复读只保证同一行两次读一致范围查询的新增行仍可能出现。解决需要完全避免幻读就用串行化或者依赖 InnoDB 的间隙锁。考试按标准答「可重复读不能防幻读」工程里知道 InnoDB 有增强即可。5.5 现象死锁日志看不懂不知道谁锁谁原因没养成看等待图或死锁日志的习惯。解决MySQL 用SHOW ENGINE INNODB STATUS看最近一次死锁里面会列出两个事务的 SQL 和持有的锁。按「谁等谁」画成图找到环回滚代价小的事务。这个技能比背答案有用得多。6. 进阶技巧用 EXPLAIN 和慢查询把答案变成工程能力搜「数据库原理及技术钱学忠答案」的人最终目标多半不只是考试而是真能上手数据库。我最后分享一个把教材知识转成工程能力的技巧用 EXPLAIN 分析你写的每一条查询。教材教你写对EXPLAIN 教你写快。-- 分析查询执行计划 EXPLAIN SELECT s.sname, sc.grade FROM student s JOIN sc ON s.sno sc.sno WHERE sc.cno C01;看几个关键列type 是访问类型ALL 是全表扫描ref 或 eq_ref 是索引查找range 是范围扫描key 是实际用的索引rows 是预估扫描行数。如果 type 是 ALL 且 rows 很大说明缺索引考虑在 sc.cno 或 sc.sno 上建索引。教材里的关系代数优化落到工程就是这一步。再进一步开启慢查询日志把执行超过阈值的 SQL 抓出来。-- 查看慢查询配置 SHOW VARIABLES LIKE slow_query_log%; SHOW VARIABLES LIKE long_query_time; -- 动态开启需权限 SET GLOBAL slow_query_log ON; SET GLOBAL long_query_time 1;参数说明long_query_time单位是秒设 1 表示超过 1 秒就记录。生产环境一般设 0.5 到 2 秒看业务容忍度。慢查询日志里重点看Rows_examined和Query_time前者大说明扫描行数多后者大说明耗时。结合 EXPLAIN 一起看基本能定位大部分性能问题。我自己的习惯是每写完一条复杂查询先 EXPLAIN 一遍确认走索引再上线。这个习惯让我在真实项目里少加了很多班。教材答案给你的是正确性EXPLAIN 给你的是可用性两者合起来才是完整的数据库能力。希望帮到你。本文还有配套的精品资源点击获取