
简介2023年上海电力大学计算机科学与技术专业《数据库原理》科目期末试卷A含答案面向高校计算机专业学生及备考数据库原理期末考试的读者。试卷覆盖SQL数据定义与安全控制、数据仓库、事务与锁、数据库恢复、关系代数、范式、分布式数据库等核心知识点题型包括填空题、判断题、选择题、简答题和综合题能够帮助考生系统检验掌握程度熟悉期末出题思路。资源为单一PDF文件共1份大小约2MB内容清晰完整既可用于考前自测也可作为阶段复习的配套练习。当前已有73人学习使用适合正在复习数据库原理课程、需要真题演练与答案解析的学生参考借鉴。1. 一份期末试卷A卷把数据库原理考成了“动手题”看到《数据库原理》期末试卷A这样的PDF很多人的第一反应是背诵名词解释实际上这份卷子考的核心早就变成了“给你一个业务场景你能不能画出ER图用SQL把表建出来再在事务和并发的边界上找出问题”。上海电力大学计算机科学与技术专业出的这份A卷恰恰把这种倾向体现得很明显选择题和填空题覆盖基础术语后面的大题几乎都落在SQL书写、函数依赖分解、事务调度上。也就是说数据库原理这门课正在从“背概念”转向“查理解”。这门课之所以让计算机科学与技术专业的学生觉得难不是因为关系代数符号多而是因为它要求一个人同时具备三种视角看数据本质的数学视角、写SQL的工程视角、调故障的运维视角。期末考试里那几道看似简单的大题其实就是把这三种视角压缩在半页纸里。所以复习数据库原理不要带着背题的心态去看任何一份带答案的试卷哪怕是上海电力大学的A卷也应该把它当作一张“能力体检表”来用。2. 数据库原理试卷的考点地图从关系代数到SQL书写2.1 关系代数与SQL的映射关系先在一张表里理清数据库原理试卷的前两道大题通常只有两种长相给你两个关系表用关系代数写查询或者反过来把SQL语句翻译成关系代数表达式。很多人栽在这里不是不会写SQL而是不习惯关系代数那种“一层一层套”的写法。关系代数里有几个操作需要分清楚选择σ是选行投影π是选列连接⋈是把两个表按条件合起来除÷则专门处理“至少包含”类的查询。期末卷里最常考的是“求选了所有课程的学生”这种题用除法写非常简洁但用SQL写往往要用到NOT EXISTS或COUNT的比较。下面把常见的SQL查询对应到关系代数操作后面写大题时可以直接对照SQL片段关系代数操作说明WHERE score 90σ(predicate)选择过滤行SELECT nameπ(attributes)投影去重列FROM Student JOIN SCStudent ⋈ SC自然连接或条件连接GROUP BY deptγ(groupBy, agg)分组聚合对应聚集操作NOT EXISTS÷除法表示全称量词看到那张对照表你应该明白一个道理SQL的书写顺序是先FROM后SELECT但关系代数的执行顺序是先乘再选再投。所以在做翻译题的时候我一般会提醒自己先把SQL的JOIN提取出来再把WHERE后的谓词拆开最后看SELECT里有没有聚合函数。试卷里如果要求“用关系代数表示查询”就不要写成“SQL伪代码”最好严格使用σ、π、⋈符号否则阅卷老师很难给分。2.2 SQL书写里的五个必练题型直接影响后面的大题数据库原理期末试卷里SQL题的分值通常占25到30分。2023年的A卷大方向依然绕不开这五类单表聚合、两表连接、三表连接带过滤、子查询配合EXISTS、修改语句的约束顺序。很多学生能写出SELECT *但遇到“选课数量大于三门的学生姓名”这种分组题就开始纠结HAVING和WHERE的区别。下面用一个典型的学生选课模型来演示两个表结构如下CREATE TABLE student ( sid CHAR(10) PRIMARY KEY, sname VARCHAR(20) NOT NULL, age INT, dept VARCHAR(20) ); CREATE TABLE sc ( sid CHAR(10), cid CHAR(6), score DECIMAL(5,2), PRIMARY KEY (sid, cid), FOREIGN KEY (sid) REFERENCES student(sid) );这里把sid定义成CHAR(10)而不是VARCHAR(10)是因为学号是定长字符串定长字段在等值查询时不需要计算长度前缀扫描效率略高。如果试卷没有指定数据类型这种细节不会扣分但在实验报告里写出来会显得更专业。接下来写两个高频查询SELECT dept, COUNT(*) AS student_cnt FROM student GROUP BY dept HAVING COUNT(*) 1;这段代码是先按dept分组然后统计每组人数再通过HAVING去掉人数不大于1的系。这里HAVING后面可以用聚合函数而WHERE不可以因为WHERE是先于分组执行的。再看一个三表连接配合子查询的写法SELECT sname FROM student WHERE sid NOT IN ( SELECT sid FROM sc WHERE cid CS101 );这段代码的语义是“没选CS101课程的学生名字”。注意NOT IN在sc.sid为NULL时会有坑因为NOT IN遇到NULL会返回“未知Unknown”导致整条查询结果为空。比较稳妥的写法是改用NOT EXISTSSELECT sname FROM student WHERE NOT EXISTS ( SELECT 1 FROM sc WHERE sc.sid student.sid AND cid CS101 );两段代码的差别在于NOT IN是集合比较NOT EXISTS是相关子查询。后者在子查询里引入了student.sid作为关联条件就算sc.sid有NULL也不会吞掉主表的结果。期末试卷里如果出现“没选某课的学生”建议直接写NOT EXISTS避免踩NULL的坑。2.3 范式判断和分解不是背定义而是画“依赖链”数据库原理试卷里有个固定节目给你一个关系模式比如R(学号, 姓名, 系名, 系主任, 课程号, 成绩)让你判断最高满足第几范式并要求分解到BCNF。很多学生看到“系主任”这种属性就懵了其实切入点是先写出函数依赖集合。比如题目隐含的依赖是学号 → 姓名, 系名系名 → 系主任(学号, 课程号) → 成绩。这里候选键是(学号, 课程号)但是学号单独就能决定姓名、系名、系主任所以存在“部分依赖”关系模式不在2NF。要分解到3NF需要把部分依赖拆出去先得到两个关系R1(学号, 姓名, 系名, 系主任)和R2(学号, 课程号, 成绩)。但R1里面又有传递依赖“学号 → 系名 → 系主任”所以还不属于3NF继续拆R11(学号, 姓名, 系名)R12(系名, 系主任)。判断范式时我一般按照这个顺序走先找候选键再看是否存在非主属性对候选键的部分依赖然后看有没有传递依赖最后看每个决定因素是不是超键。试卷里的分解题只要把每一步依赖链画出来答案基本就有了一半。注意分解的时候要保持无损连接如果两个分解后的关系模式共享一个公共属性并且这个属性是其中一个的键那就可以通过自然连接恢复原始关系。3. 事务、并发控制与恢复试卷里的“计算题”重头戏3.1 ACID与两段锁协议先用SQL事务把概念钉住数据库原理试卷常考的“事务四大特性”不是让你默写而是给你一个场景两个同时转账的会话问你哪个特性被破坏或者要求用调度证明冲突可串行化。先看ACID在SQL里怎么落地。通常用BEGIN TRANSACTION开启一个事务在结束时用COMMIT提交如果中间出错就用ROLLBACK回滚。下面的例子展示了事务的原子性和持久性控制BEGIN TRANSACTION; UPDATE account SET balance balance - 100 WHERE accno A001; UPDATE account SET balance balance 100 WHERE accno B002; IF ERROR 0 BEGIN ROLLBACK TRANSACTION; END ELSE BEGIN COMMIT TRANSACTION; END这个写法是T-SQL风格两个UPDATE语句要么都成功要么都回滚。其中ERROR是数据库引擎返回的全局错误码如果第一条语句成功、第二条语句因为约束失败就可以捕获到非零值触发ROLLBACK。两段锁协议2PL则是从数据库引擎层面保证调度正确性的机制。它的核心要求是事务必须分两个阶段释放锁先增长、后收缩。试卷里经常让你画一个事务的锁请求序列然后问你“是否遵守两段锁协议”。注意一个常见误区两段锁协议的“增长阶段”可以多次申请锁但不能释放锁一旦开始释放锁就不能再申请新锁。严格两段锁协议则要求所有锁在提交时统一释放这个差异在死锁判断里很关键。3.2 冲突可串行化判断优先图画法三步走并发调度是数据库原理期末试卷的大题常客。给你一个包含T1、T2两个事务的调度要求判断它是否冲突可串行化。我习惯的解法是先画优先图三步走。第一步找出调度中所有冲突操作。冲突是指两个来自不同事务的操作访问同一数据项并且至少有一个是写操作。第二步对每一对冲突操作根据事务执行顺序画有向边。第三步检查优先图是否有环。如果无环则调度冲突等价于某个串行调度如果有环则绝对不可串行化。举一个例子考虑三个事务的调度片段时间事务操作t1T1READ(A)t2T2READ(B)t3T1WRITE(A)t4T2WRITE(B)这里存在冲突T1的WRITE(A)和自身其他操作不是事务间冲突而T2的READ(B)与T2的WRITE(B)也是同一个事务。如果T1和T2之间没有访问同一数据项那么优先图没有任何边当然就是冲突可串行化的。真正容易误判的情况是两个事务同时访问A和B例如T1先READ(A)T2后WRITE(A)那么T1在T2之前读A后面T2又写A二者冲突边从T1指向T2。如果优先图出现环就要考虑使用“回滚”或“死锁检测”机制来恢复。试卷里除了要求判断还会附带问“应该回滚哪个事务”一般答案是回滚发生冲突较晚的那个事务这样能减少级联回滚。3.3 日志与恢复机制Redo和Undo怎么选数据库原理期末的计算题里“故障恢复”经常以日志序列的形式出现。给你一个日志片段包含T1, A, 100, 200这种格式再告诉你系统在某个时刻崩溃要求说明哪些事务需要REDO哪些需要UNDO。日志记录格式通常是事务ID, 数据项, 旧值, 新值。崩溃恢复时检查日志中是否包含事务的COMMIT记录如果事务已经提交但缓冲区中修改可能还没刷盘就需要REDO如果事务没有提交说明它对数据库的修改是需要撤销的就UNDO。判断的时候我一般先找出所有“没有COMMIT”的事务列表再把“有COMMIT但仍在某些检查点之后”的事务单独拎出来。比如下面这段日志日志编号内容1T1, A, 100, 2002T2, B, 50, 803T1, COMMIT4T2, C, 0, 10如果系统在编号4之后崩溃则T1已经COMMIT需要REDOT2未COMMIT需要UNDO。注意这里不需要重放整个日志只需要从最近的检查点开始检查每条日志的提交状态。试卷可能会画一个带检查点的序列然后让你写出恢复动作。这个考点没有太多技巧但非常容易漏掉“检查点之前的已提交事务不需要REDO”。4. 索引、查询优化与存储试卷里的“设计题”怎么看4.1 B树索引到底解决了什么问题数据库原理期末试卷里索引相关的题目常常以“为什么数据库不用二叉搜索树”来开头。你需要回答B树的高度更低磁盘IO次数更少并且所有数据都在叶子节点形成有序链表方便范围查询。一张B树的典型参数表可以这样记参数含义典型值阶数 m非根节点最多 m 个指针128或256高从根到叶子的路径长度2~4层叶子链路叶子节点按序连接支持范围扫描期末试卷的计算题可能是“一个B树每个节点能存放100个键假设有100万条记录树的高度是多少”这里实际上说的是100个键非根节点最多101个指针根节点至少2个指针。高度估算公式是若节点扇出为F记录数为N叶子层有N/F个节点上一层有N/F^2个最后算出层数。用log(F, N)近似log(100, 1000000)约等于3所以树高大概是3到4层。索引设计题里还有一个常考“聚簇索引 vs 非聚簇索引”的对比。聚簇索引的表数据物理上按索引键排序所以每个表只能有一个聚簇索引非聚簇索引在叶节点存的是行指针或主键值回表才是它的主要代价。试卷里如果问“为什么主键通常建聚簇索引”可以答“数据插入默认按主键顺序排列减少页分裂查询主键时一次IO直接命中数据页”。4.2 查询优化器做了什么从EXPLAIN看懂低价计划试卷里给一条SQL让你说明优化器可能选择的执行计划这类题目本质上问的是等价变换和启发式规则。比如哪里有选择下推哪里做连接顺序重排哪里把子查询改写为连接。很多学生只背“先投影后选择”这个顺序实际上优化器做的事情远不止这样。以MySQL为例查看执行计划用EXPLAINEXPLAIN SELECT s.sname, sc.score FROM student s JOIN sc ON s.sid sc.sid WHERE sc.cid CS101;EXPLAIN输出中的possible_keys显示可用索引key是实际选的索引type列能看到ALL说明全表扫描ref或eq_ref说明走了索引等值匹配。上面这个查询如果sc(cid)有索引优化器可能会先通过索引找出cidCS101的行再去访问student表如果没有索引就只能把sc全表扫描一遍。期末试卷里不会让你背EXPLAIN的输出列但会问“添加索引后的执行计划变化”。回答的时候记住一个核心原则查询优化器倾向于减少中间结果集的行数所以WHERE条件里的过滤优先级最高。这也解释了为什么“在基数大的列上建索引”有效而性别这种只有两个值的列建索引并不能显著减少扫描量。4.3 从实验报告反推操作题别只盯着选择题数据库原理课程实验报告不是只有“数据库搭建”步骤更多是让你在给定环境里验证这两类一类是索引前后的查询耗时对比另一类是事务隔离级别对读写的影响。期末考试的操作题本质是把实验报告里的观察结果用笔试的形式问出来。举例来说实验报告里常见的测试语句是SET TRANSACTION ISOLATION LEVEL READ COMMITTED; BEGIN TRANSACTION; SELECT * FROM account WHERE accno A001; -- 模拟并发另一个会话同时读写 COMMIT;你需要能回答出在READ COMMITTED隔离级别下当前事务读取时看到的是已提交数据所以其他事务提交前修改的数据不会出现但如果两次SELECT之间其他事务提交了修改你的两次读取结果会不一致这就是“不可重复读”。隔离级别从低到高的变化能解决哪些并发问题这个表就是操作题的最后一问。隔离级别脏读不可重复读幻读读未提交可能可能可能读已提交不会可能可能可重复读不会不会可能InnoDB里可规避可串行化不会不会不会这张表不仅适用于实验报告还是期末试卷里最难拿全分的部分。因为很多学生会背却没意识到“可重复读”仍然可能发生幻读。在MySQL InnoDB默认的REPEATABLE READ下通过next-key lock实际上锁住了范围所以标准SQL里的幻读在大多数场景下不会出现但试卷通常讲的是标准SQL行为要按照表格来答。5. 用一套“三遍式”自测流程把试卷A卷变成自己的知识点索引最后这部分给一份可以直接照做的期末自测方法。无论你拿到的题目来自哪所学校的A卷复习流程都可以压缩成三遍第一遍限时做卷子第二遍按错题反查理论第三遍把算法题重新手写一遍。我习惯用一张总表来管理这三轮安排项目第1轮第2轮第3轮时间安排考前1周考前3天考前1天任务做完整试卷只做错题对应章节手写SQL和调度答案重点选择题、填空题函数依赖、范式分解并发调度、B树、日志恢复自检方式估分翻教材找概念不看答案默写第二轮反查的作用是帮你把错题映射到教材具体章节。比如NOT IN的NULL问题映射到了SQL子查询语义优先图有环问题映射到了数据库理论中“可恢复调度”和“级联回滚”。这样做的好处是每道题的错因不会只停留在“记错了”这个层面而是变成数据库设计里的一条边界条件。第三轮手写针对的是卷面表达不是键盘输入。期末试卷里的SQL题是纸笔作答所以你必须练会在没有补全提示的环境下写出完整的CREATE TABLE和SELECT语句。我推荐你准备一组自测SQL在复习最后一天刷一遍-- 自测找出选课门数低于2门的学生 SELECT s.sname FROM student s LEFT JOIN sc ON s.sid sc.sid GROUP BY s.sid, s.sname HAVING COUNT(sc.cid) 2;这组自测SQL包含了外连接、分组、聚合和HAVING条件覆盖了期末SQL题的绝大多数考点。写完以后再从EXPLAIN的角度思考如果给sc(sid)加索引这个查询的执行计划会有什么变化答案是可以计算sc.sid的基数通过等值索引减少回表次数。这样一道复习题就同时打通了SQL、索引和查询优化三个章节。如果你手边有上海电力大学这份A卷先别急着看答案把其中的SQL题和事务调度题当作自测基准用上面的流程走两遍基本就能在考试时避开大部分陷阱。本文还有配套的精品资源点击获取