简介:这份数据库期末考试试题及答案面向高校计算机及相关专业学生,用于期末复习、自测与查漏补缺,也可供备考数据库原理类课程的读者对照练习。资源以doc文档形式提供,压缩包内共1个文件,大小约118KB,内容为一份完整的期末试卷及配套答案,涵盖单项选择题、填空题等题型。试题覆盖数据库系统核心与DBMS、数据模型与概念模型、数据独立性、关系数据模型、E-R模型转换、数据库设计、关系规范化、事务隔离性、封锁协议与数据库恢复等核心知识点,并配有标准答案与解析要点,便于读者逐题核对、理解易错概念。目前已有3787人学习下载,适合需要系统梳理考点、快速检验掌握程度的读者使用。
1. 数据库期末考试试题及答案:从背题到真懂,中间隔着一次动手复现
数据库期末考试题,绝大多数人拿到手的第一反应是“背”。选择题背选项,填空题背关键字,简答题背条目,大题背SQL模板。背完上考场,考完就忘,下次遇到同样的查询需求还是写不出来。问题出在:试题和答案本身不是知识,它们只是知识被压缩后的快照。你背的是快照,不是产生快照的那台机器。
这个标题真正指向的需求有三层。第一层是应试:需要一套结构清晰、覆盖核心考点的题目和参考答案,能对着复习。第二层是理解:为什么这道题考这个知识点,换个条件答案会怎么变。第三层是迁移:把试题里的SQL、范式判断、事务分析搬到真实场景里,能自己出题、自己验证。这篇文章按这三层来拆,重点放在第二层和第三层——因为只做第一层,你永远在追下一套题。
适合谁看:正在准备数据库期末的在校生,需要一套可复现的复习路径;已经考完但发现自己“只会做题不会用”的开发者,想借试题这个壳把底层逻辑补回来;以及需要出题或组卷的人,想知道一道好题应该卡在哪个点上。
2. 试题的四类题型分别卡什么能力:先看懂再动手
2.1 选择题和填空题:考的是边界条件,不是定义
很多人复习选择题的方式是把答案抄一遍,然后反复看。这没用。选择题的真正价值在于:每个错误选项都对应一个常见的理解偏差。比如“关系数据库中,视图是否可以更新”这类题,正确选项往往附带“在特定条件下”这个限定,而错误选项就是把条件去掉后的绝对化表述。
我一般会这样处理一套选择题:先把题干里的关键词圈出来,然后在旁边写“这个条件去掉后答案会变成什么”。举个例子:
-- 题干:以下哪个操作会隐式提交事务? -- A. SELECT B. INSERT C. CREATE TABLE D. UPDATE -- 答案:C -- 但真正要记的是:DDL 语句(CREATE/ALTER/DROP/TRUNCATE)在多数数据库里会隐式提交 -- 验证方式:在事务里执行 CREATE TABLE,然后 ROLLBACK,看表是否还在逻辑说明:这道题表面考“哪个是DDL”,实际考的是“事务边界在哪里”。参数说明:不同数据库对DDL的处理有差异,MySQL的InnoDB引擎下DDL会隐式提交,但某些数据库支持事务性DDL。你复习时如果只记“C”,换一道“TRUNCATE是否隐式提交”就又不会了。
填空题的复习策略类似。填空题的答案通常是一个术语或一个数字,但你要问自己:这个术语的定义边界是什么,这个数字在什么版本、什么配置下成立。比如“第三范式的定义是消除____依赖”,答案是“传递函数依赖”。但你要能举出一个反例:什么表满足3NF但不满足BCNF。
2.2 简答题:考的是因果链,不是条目列表
简答题的参考答案通常是一段话,但阅卷时是按点给分。这意味着你背条目就能拿分,但拿不到“理解”的分。我的做法是把每个简答题的答案拆成“因为…所以…如果…则…”的因果链。
以“为什么需要事务隔离级别”为例,参考答案可能写“为了防止脏读、不可重复读、幻读”。但真正的因果链是:并发事务互相干扰 → 产生三类异常 → 用锁或MVCC来隔离 → 隔离越强并发越低 → 所以需要分级。你把这个链条写出来,简答题的答案自然就有了,而且换一道“MVCC如何实现可重复读”也能答。
-- 验证不可重复读的最小实验(以MySQL为例) -- 会话A START TRANSACTION; SELECT balance FROM account WHERE id = 1; -- 假设读到 100 -- 会话B UPDATE account SET balance = 200 WHERE id = 1; COMMIT; -- 会话A再次查询 SELECT balance FROM account WHERE id = 1; -- 在READ COMMITTED下读到200,在REPEATABLE READ下仍读到100 COMMIT;逻辑说明:这个实验比背“不可重复读的定义”有用得多。参数说明:MySQL默认隔离级别是REPEATABLE READ,所以会话A第二次读到的还是100。如果你把隔离级别改成READ COMMITTED,结果就变了。这个差异就是简答题里“隔离级别影响”的具体体现。
2.3 SQL大题:考的是查询分解能力,不是语法记忆
SQL大题是整张试卷里最能拉开差距的部分。常见题型包括:多表连接、子查询、聚合与分组、窗口函数、递归查询。很多人卡住不是因为不会写JOIN,而是因为读不懂题目的业务逻辑。
我的习惯是:拿到SQL大题,先不写SQL,先用自然语言把查询目标拆成三步——要什么数据、从哪些表来、按什么条件过滤和分组。拆完再写SQL,写完再用一个小数据集验证。
-- 典型题目:查询每个部门薪资最高的员工姓名和薪资 -- 第一步:要什么 → 员工姓名、薪资、部门 -- 第二步:从哪来 → employee 表,包含 dept_id, name, salary -- 第三步:怎么过滤 → 每个部门内 salary 最大 -- 写法一:相关子查询 SELECT e.name, e.salary, e.dept_id FROM employee e WHERE e.salary = ( SELECT MAX(salary) FROM employee WHERE dept_id = e.dept_id ); -- 写法二:窗口函数(MySQL 8.0+) SELECT name, salary, dept_id FROM ( SELECT name, salary, dept_id, RANK() OVER (PARTITION BY dept_id ORDER BY salary DESC) AS rk FROM employee ) t WHERE rk = 1;逻辑说明:两种写法结果在“薪资无并列”时一致,但有并列时相关子查询会返回多行,窗口函数用RANK也会返回多行,用ROW_NUMBER则只返回一行。参数说明:PARTITION BY指定分组列,ORDER BY指定排序方向,RANK/ROW_NUMBER/DENSE_RANK的区别是并列时的排名处理。考试时如果题目没提并列,两种写法都可以;如果提了“最高薪资可能有多人”,就要注意返回多行是否符合题意。
2.4 范式判断与事务分析:考的是权衡,不是死记
范式判断题的套路是给一个关系模式加一组函数依赖,让你判断属于第几范式并分解。事务分析题通常给一个并发调度,让你判断是否可串行化。这两类题的共同点是:答案不唯一,但考试有标准答案。你要做的是理解标准答案背后的权衡逻辑。
范式分解的核心权衡是:分解越细,冗余越少,但连接越多,查询越慢。所以3NF和BCNF的选择不是“越高越好”,而是看业务对一致性和性能的侧重。事务可串行化的判断,核心是看冲突操作之间有没有环。
-- 验证范式分解:以学生选课为例 -- 原始表:SC(学号, 课程号, 成绩, 教师名) -- 函数依赖:学号+课程号 → 成绩;课程号 → 教师名 -- 问题:教师名部分依赖于课程号,存在传递依赖 -- 分解为: -- SC1(学号, 课程号, 成绩) -- SC2(课程号, 教师名) -- 验证无损连接:SC1 ⋈ SC2 能否还原原始表 SELECT * FROM SC1 NATURAL JOIN SC2;逻辑说明:这个分解消除了传递依赖,达到3NF。参数说明:NATURAL JOIN会自动按同名列连接,这里同名列是课程号。你要验证的是:分解后连接的结果是否和原始表完全一致,以及是否丢失了任何函数依赖。考试时如果要求达到BCNF,还要检查每个决定因素是否都是候选键。
3. 从试题到可运行验证:用SQLite搭一个最小复习环境
3.1 为什么选SQLite而不是MySQL或PostgreSQL
复习数据库试题,你不需要一个完整的数据库服务器。你需要的是一个能快速建表、插入数据、执行查询、看到结果的环境。SQLite满足这三个条件,而且零配置、单文件、跨平台。MySQL和PostgreSQL当然更接近生产环境,但安装和配置会消耗你本来就不多的复习时间。
常见做法是:用SQLite验证选择题和SQL大题,用MySQL验证事务和隔离级别。因为SQLite对事务隔离级别的支持比较有限,默认是SERIALIZABLE,不方便演示READ COMMITTED和REPEATABLE READ的差异。但如果你只是验证SQL语法和查询逻辑,SQLite足够了。
# 安装SQLite(多数系统自带,没有的话用包管理器) # macOS: brew install sqlite # Ubuntu/Debian: sudo apt install sqlite3 # Windows: 下载 sqlite-tools 压缩包,解压后把 sqlite3.exe 放到 PATH # 创建一个复习用的数据库文件 sqlite3 exam_review.db # 在SQLite提示符下建表 CREATE TABLE student ( sno TEXT PRIMARY KEY, sname TEXT NOT NULL, dept TEXT ); CREATE TABLE course ( cno TEXT PRIMARY KEY, cname TEXT NOT NULL, credit INTEGER ); CREATE TABLE sc ( sno TEXT, cno TEXT, grade REAL, PRIMARY KEY (sno, cno), FOREIGN KEY (sno) REFERENCES student(sno), FOREIGN KEY (cno) REFERENCES course(cno) );逻辑说明:这三张表覆盖了试题里最常见的连接查询场景。参数说明:PRIMARY KEY指定主键,FOREIGN KEY指定外键,NOT NULL约束非空。SQLite默认不强制外键,需要执行PRAGMA foreign_keys = ON;才能生效。这个细节本身就是一道选择题的考点。
3.2 把试题里的SQL大题变成可执行的验证脚本
复习SQL大题最有效的方式是:把题目里的描述转成建表和插入语句,然后自己写查询,再对照参考答案。这个过程会暴露你“以为会了”和“真的会了”之间的差距。
-- 插入模拟数据 INSERT INTO student VALUES ('S001', '张三', '计算机'); INSERT INTO student VALUES ('S002', '李四', '计算机'); INSERT INTO student VALUES ('S003', '王五', '数学'); INSERT INTO course VALUES ('C001', '数据库', 4); INSERT INTO course VALUES ('C002', '数据结构', 3); INSERT INTO course VALUES ('C003', '高等数学', 5); INSERT INTO sc VALUES ('S001', 'C001', 85); INSERT INTO sc VALUES ('S001', 'C002', 90); INSERT INTO sc VALUES ('S002', 'C001', 78); INSERT INTO sc VALUES ('S002', 'C003', 88); INSERT INTO sc VALUES ('S003', 'C003', 92); -- 题目:查询选修了“数据库”课程且成绩大于80的学生姓名 SELECT s.sname FROM student s JOIN sc ON s.sno = sc.sno JOIN course c ON sc.cno = c.cno WHERE c.cname = '数据库' AND sc.grade > 80; -- 题目:查询每个学生的总学分(只算及格课程) SELECT s.sname, SUM(c.credit) AS total_credit FROM student s JOIN sc ON s.sno = sc.sno JOIN course c ON sc.cno = c.cno WHERE sc.grade >= 60 GROUP BY s.sno, s.sname;逻辑说明:第一道题考三表连接加过滤,第二道题考连接加聚合加过滤。参数说明:JOIN默认是INNER JOIN,只返回匹配的行;GROUP BY后面要跟所有非聚合列,否则在严格模式下会报错。SQLite对GROUP BY的约束比较宽松,但考试时如果用的是MySQL的ONLY_FULL_GROUP_BY模式,漏写sname就会报错。
3.3 用EXPLAIN看查询计划,理解试题背后的性能考点
很多试题会问“哪个查询效率更高”或者“索引应该建在哪个列上”。这类题如果只背答案,换个场景就懵了。用EXPLAIN看查询计划,能把抽象的效率问题变成具体的扫描行数和索引使用情况。
-- 在SQLite中查看查询计划 EXPLAIN QUERY PLAN SELECT s.sname FROM student s JOIN sc ON s.sno = sc.sno WHERE sc.grade > 80; -- 输出示例: -- SCAN sc -- SEARCH s USING INTEGER PRIMARY KEY (rowid=?) -- 在sc.grade上建索引后再看 CREATE INDEX idx_sc_grade ON sc(grade); EXPLAIN QUERY PLAN SELECT s.sname FROM student s JOIN sc ON s.sno = sc.sno WHERE sc.grade > 80; -- 输出示例: -- SEARCH sc USING INDEX idx_sc_grade (grade>?) -- SEARCH s USING INTEGER PRIMARY KEY (rowid=?)逻辑说明:第一次输出显示对sc表做了全表扫描(SCAN),建索引后变成索引查找(SEARCH USING INDEX)。参数说明:EXPLAIN QUERY PLAN是SQLite的命令,MySQL里用EXPLAIN,PostgreSQL里用EXPLAIN ANALYZE。考试时如果问“为什么在grade上建索引能加速”,你要能说出“因为避免了全表扫描,直接定位到满足条件的行”。
4. 避坑:复习数据库试题时最容易翻车的五个地方
4.1 把参考答案当唯一真理,忽略数据库差异
现象:试题答案写“SELECT * FROM t WHERE name LIKE '%abc%' 可以用索引”,你背下来,结果在MySQL的InnoDB上发现全表扫描。
原因:前缀模糊匹配(LIKE 'abc%')可以用索引,但前后都带通配符(LIKE '%abc%')通常用不了B+树索引。不同数据库的优化器行为也有差异。
解决:遇到这类题,先确认题目默认的数据库类型。如果没有指定,就按标准SQL的通用行为来答,同时在笔记里标注“MySQL下实际行为可能不同”。复习时用SQLite或MySQL实际跑一下EXPLAIN,比背答案可靠。
4.2 事务隔离级别的实验做了一半就下结论
现象:你在MySQL里开了两个会话,想验证“不可重复读”,结果发现会话A第二次读到的数据和第一次一样,就以为MySQL不支持不可重复读。
原因:MySQL默认隔离级别是REPEATABLE READ,在这个级别下确实不会出现不可重复读。你要先改成READ COMMITTED才能看到。
解决:实验前先确认当前隔离级别,用SELECT @@transaction_isolation;(MySQL 8.0+)或SELECT @@tx_isolation;(MySQL 5.7)。改级别用SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;。每次实验只改一个变量,否则你分不清是隔离级别的影响还是其他配置的影响。
4.3 范式分解后忘了验证无损连接和依赖保持
现象:你把一个表分解成三个表,觉得“每个表都满足3NF了”,但一连接发现数据对不上,或者某个函数依赖丢了。
原因:范式分解有两个硬性要求——无损连接和依赖保持。只满足范式级别但不满足这两个条件的分解是无效的。
解决:分解后一定要做两件事。第一,用NATURAL JOIN或指定列连接,看能否还原原始表。第二,列出原始的所有函数依赖,检查每个依赖是否在某个分解后的表中仍然成立。如果某个依赖跨了多个表,说明依赖丢了,需要调整分解方案。
4.4 SQL写对了但结果不对,其实是NULL在捣乱
现象:你写了一个NOT IN子查询,逻辑上没问题,但查询结果为空。换成NOT EXISTS就对了。
原因:NOT IN遇到子查询结果里有NULL时,整个条件会变成UNKNOWN,导致没有行被返回。这是SQL里最经典的坑之一。
解决:用NOT EXISTS替代NOT IN,或者在子查询里加WHERE col IS NOT NULL。考试时如果题目涉及“不在某个集合里”的语义,优先写NOT EXISTS,除非题目明确要求用NOT IN。
-- 有问题的写法 SELECT sname FROM student WHERE sno NOT IN (SELECT sno FROM sc WHERE grade < 60); -- 如果sc表里有sno为NULL的行,上面的查询返回空 -- 修正写法一:排除NULL SELECT sname FROM student WHERE sno NOT IN (SELECT sno FROM sc WHERE grade < 60 AND sno IS NOT NULL); -- 修正写法二:用NOT EXISTS SELECT sname FROM student s WHERE NOT EXISTS ( SELECT 1 FROM sc WHERE sc.sno = s.sno AND sc.grade < 60 );4.5 复习时只看不写,考场上手生
现象:选择题和简答题背得很熟,但SQL大题写的时候卡在语法上,或者忘了GROUP BY后面要跟哪些列。
原因:阅读和书写是两种不同的认知活动。你看懂一个查询,不代表你能在压力下写出来。
解决:每复习一道SQL大题,先不看答案,自己在SQLite里写一遍。写完执行,看结果对不对。不对就调,调到对为止。然后再看参考答案,对比写法差异。这个过程比读十遍答案都管用。我一般会给自己定一个规矩:每道大题至少手写两遍,第一遍允许查语法,第二遍闭卷写。
5. 进阶:用试题反向出题,把复习变成验证
复习到后期,最有效的检验方式不是“再做一套题”,而是“自己出一套题”。出题的过程会逼你从“知道答案”升级到“知道为什么这个答案值得考”。
具体做法是:拿一个你熟悉的业务场景,比如“学生选课”或“订单管理”,先设计表结构和函数依赖,然后自己判断范式级别,自己写查询,自己设计事务并发场景。出完题后,用SQLite或MySQL把整个场景跑一遍,验证你的答案是否自洽。
-- 自出题示例:设计一个订单表,包含订单号、客户号、商品号、数量、单价、下单时间 -- 函数依赖:订单号+商品号 → 数量;商品号 → 单价;订单号 → 客户号、下单时间 -- 判断范式:单价部分依赖于商品号,存在部分依赖,不属于2NF -- 分解:订单表(订单号, 客户号, 下单时间)、订单明细(订单号, 商品号, 数量)、商品表(商品号, 单价) CREATE TABLE orders ( order_id TEXT PRIMARY KEY, customer_id TEXT, order_time TEXT ); CREATE TABLE order_item ( order_id TEXT, product_id TEXT, quantity INTEGER, PRIMARY KEY (order_id, product_id) ); CREATE TABLE product ( product_id TEXT PRIMARY KEY, unit_price REAL ); -- 自问:查询每个客户的总消费金额 SELECT o.customer_id, SUM(oi.quantity * p.unit_price) AS total FROM orders o JOIN order_item oi ON o.order_id = oi.order_id JOIN product p ON oi.product_id = p.product_id GROUP BY o.customer_id; -- 自问:这个查询在数据量大时怎么优化? -- 自答:在order_item的order_id和product_id上建索引,在product的product_id上建主键索引 -- 如果按客户分组频繁,可以考虑在orders的customer_id上建索引逻辑说明:这个自出题的过程覆盖了范式判断、表设计、连接查询、聚合、索引优化五个考点。参数说明:PRIMARY KEY (order_id, product_id)是复合主键,保证同一订单同一商品只有一条记录。SUM(oi.quantity * p.unit_price)先算每行的金额再求和,注意不要写成SUM(quantity) * SUM(unit_price),那是错的。
出完题后,你可以拿它去和同学交换做,或者隔一周自己再做一遍。如果一周后你还能在不看答案的情况下写对,说明这个知识点真的掌握了。如果写错了,错的地方就是你复习的盲区。
我自己的习惯是:每复习完一个章节,就出一套5道题的小卷子,包含2道选择、1道简答、2道SQL。出完不马上做,隔两天再做。这个间隔让记忆稍微冷却,暴露出的问题更真实。考数据库期末也好,考任何技术认证也好,这套方法都比单纯刷题管用。希望帮到你。
本文还有配套的精品资源,点击获取