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

数据库工程能力压力测试:从ER建模到SQL避坑实战

数据库工程能力压力测试:从ER建模到SQL避坑实战 ★ FEATURED ARTICLE
简介本资源为中南大学数据库课程期末考试真题试卷及配套复习纲要面向计算机、软件工程等专业本科生及数据库自学者助力系统梳理核心考点、查漏补缺与应试冲刺。试卷涵盖选择题、填空题、术语解释与简答题四大题型内容紧扣数据库原理教学重点包括三级模式结构、ER模型与关系模型对比、SQL语言分类DDL/DML、索引机制、事务ACID特性、并发控制问题如丢失更新、规范化理论1NF/2NF/3NF及数据库设计六步法等高频考点。资源为单个Word文档.doc大小164KB结构清晰前半部分为29页完整试题与标准答案后半部分附带7章详细复习提纲每章标注重点与作业提示便于分模块精读与背诵。目前已有355人学习下载是备考高校数据库课程考试的高价值实战资料。1. 中南大学数据库试题不是题库是关系型数据库工程能力的「压力测试清单」这不是一份拿来背答案的期末复习卷而是一套被反复验证过、能真实暴露你数据库工程能力断层的「压力测试清单」。我带过三届数据库课程设计每次开课前都会把这份材料拆开重跑一遍——不是为了对答案而是看哪些知识点在实操中会突然“失联”比如写一个看似简单的SELECT ... WHERE 子查询学生常卡在NOT EXISTS的双重否定嵌套逻辑里又比如建索引时明明写了CREATE CLUSTERED INDEX执行却报错说“表已存在聚簇索引”结果发现是主键默认建了聚簇索引自己又重复建了一次再比如规范化分析题里“一个系只有一名主任”这个业务约束若没意识到它隐含所在系 → 系主任的函数依赖后续推导 3NF 就全盘崩塌。它覆盖的不是碎片化考点而是数据库工程师日常要闭环处理的完整链路从 ER 图建模CH2→ 关系模式转换CH3→ SQL DDL/DML 实现CH4→ 并发控制与事务隔离CH5→ 规范化诊断与重构CH6→ 应用系统级设计CH7。每道题背后都对应一个真实场景第 5 题“求选修了全部课程的学生”本质是生产环境里常见的「用户全量行为匹配」问题第 7 题“插入/更新学生记录”直指 OLTP 系统中高频的 CRUD 边界校验而试卷2第 14 题问“实现事务隔离性的子系统”答案是并发控制子系统——这恰恰是高并发电商下单时库存扣减不超卖的核心防线。适合谁正在准备数据库原理考试的学生但更关键的是刚接手公司遗留数据库维护任务的初级 DBA、需要写复杂报表 SQL 的 BI 工程师、或是正为微服务间数据一致性头疼的后端开发者。它不教你怎么考高分而是逼你回答“当SELECT * FROM student WHERE age (SELECT MAX(age) FROM student WHERE deptIS)在千万级表上执行超时你第一反应是加索引、改写子查询还是怀疑统计信息过期”——这种肌肉记忆才是这份试题真正的价值。2. 从 ER 模型到关系模式为什么你的 E-R 图总在转换时“漏掉”关键约束ER 模型是数据库设计的起点但多数人只把它当绘图工具忽略了它和后续 SQL 实现之间的强耦合。中南大学试题里 CH2 和 CH6 的题目如试卷3第五大题第 2 小题反复验证一个事实ER 图里没画出来的约束SQL 里就永远缺一条 CHECK 或 FOREIGN KEY。下面拆解三个最易翻车的转换环节。2.1 键约束的 ER 显式化别让“唯一性”藏在文字描述里看试卷1第 6 题借阅书号、书名库存数读者号借期还期假如同一本书允许一个读者多次借阅但不能同时对一种书借多本。表面看是业务规则实则是复合主键 唯一性约束的 ER 编码。“同一种书不能同时借多本” →(书号, 读者号)必须唯一但注意不是主键因允许同一读者多次借同一本书只要时间不重叠而是UNIQUE(书号, 读者号)约束“不能同时借多本”的“同时”二字暗示需配合借期/还期字段做范围检查这已超出基础约束范畴需触发器或应用层控制。提示ER 图中必须用双线椭圆标出“候选键”用双线矩形标出“弱实体”否则转换时必然遗漏。试卷2第 2 题问“n:m 联系如何实现”标准答案是“增加一个关系”但没说清这个新关系的主键必须是两端实体主键的组合——这就是 ER 图里用菱形连接线标注n:m后必须在菱形内写明“借阅ID”或直接标(书号, 读者号)作为主键。2.2 弱实体与标识关系为什么你的外键总报“违反参照完整性”试卷3第五大题第 2 小题给出的关系模式学号姓名所在系系主任课程名成绩并说明“一个系只有一名主任”。这里系主任是弱属性其存在完全依赖于所在系。若直接建表CREATE TABLE student ( sno CHAR(10) PRIMARY KEY, sname VARCHAR(20), dept VARCHAR(20), dept_head VARCHAR(20), -- ❌ 错误未关联到系表 course_name VARCHAR(50), score DECIMAL(4,1) );问题来了dept_head怎么保证不填错如果某系换主任要批量 UPDATE 所有学生记录正确做法是拆成两个表并用外键强制关联-- 先建系表主键即系名或独立系ID CREATE TABLE department ( dept_name VARCHAR(20) PRIMARY KEY, dept_head VARCHAR(20) NOT NULL ); -- 学生表引用系表 CREATE TABLE student ( sno CHAR(10) PRIMARY KEY, sname VARCHAR(20), dept_name VARCHAR(20) NOT NULL, course_name VARCHAR(50), score DECIMAL(4,1), FOREIGN KEY (dept_name) REFERENCES department(dept_name) -- ✅ 强制参照 );参数说明FOREIGN KEY后的字段类型、长度、是否允许 NULL 必须与被引用表的主键完全一致。试卷1第 10 题选项 D “E-R 模型” 正是强调这种实体-联系抽象而非直接映射字段。2.3 多值属性与派生属性别把“计算字段”当普通列存试卷1第七大题第 6 小题要求查询选修了全部课程的学生学号和姓名其参考答案用NOT EXISTS嵌套本质是关系代数除法运算的 SQL 实现。但很多学生试图用COUNT(*)统计课程总数再比对这就踩进了“派生属性陷阱”——学生选课数是派生值不应作为表字段存储而应在查询时实时计算。正确思路是获取所有课程集合C对每个学生S检查C - S.选课集合是否为空若为空则S选修了全部课程。SQL 实现必须用NOT EXISTS如试卷1参考答案所示因为COUNT方案在并发环境下可能因读取时机不同导致幻读。ER 图中这类属性应标为虚线椭圆派生属性明确告知设计者“此值不可存需计算”。3. SQL 实战避坑DDL/DML 语句里藏着的 5 个“静默失败”陷阱中南大学试题的 SQL 部分CH4、试卷六、七看似简单但每道题都是生产环境常见故障的微缩版。我曾帮某高校教务系统排查过一次慢查询根源竟是试卷1第六大题第 3 小题的索引写法CREATE INDEX teach ON teacher(bh);—— 表名写错成teach索引根本没建上而开发人员只查了SHOW INDEX却没验证索引是否生效。以下是实测高频的 5 个静默失败点。3.1 索引创建失败却不报错大小写、空格与关键字冲突现象执行CREATE INDEX teach ON teacher(bh);后SHOW INDEX FROM teacher;查不到索引但命令返回成功。原因MySQL 8.0 默认区分大小写若表名实际为TEACHER而语句写teacher索引会建在不存在的表上MySQL 不报错teach是部分版本的关键字如 MariaDB 的TEACH函数导致解析异常字段名bh若在建表时定义为BH大写而索引语句用小写在某些配置下会失败。解决# 1. 先确认表名和字段名的真实大小写 SHOW CREATE TABLE teacher; # 2. 用反引号强制指定名称推荐 CREATE INDEX idx_teacher_bh ON teacher (BH); # 3. 验证索引是否生效关键 EXPLAIN SELECT * FROM teacher WHERE BH 123; # 查看 key 列是否显示 idx_teacher_bh3.2 ALTER TABLE ADD COLUMN 语法差异NULL 默认值的隐形炸弹现象试卷1第六大题第 2 小题ALTER TABLE teacher ADD COLUMN wcf int;在 MySQL 5.7 上执行后新列wcf全为NULL但业务要求“误餐费默认为 0”。原因不同数据库对ADD COLUMN的NOT NULL处理不同MySQL若未指定NOT NULL默认允许 NULL且不设默认值PostgreSQL必须显式声明DEFAULT 0否则报错SQL Server可设DEFAULT 0 WITH VALUES强制填充旧记录。解决-- MySQL 安全写法兼容旧数据 ALTER TABLE teacher ADD COLUMN wcf INT DEFAULT 0 NOT NULL; -- PostgreSQL 必须写 ALTER TABLE teacher ADD COLUMN wcf INTEGER DEFAULT 0; -- SQL Server 强制填充历史数据 ALTER TABLE teacher ADD wcf INT DEFAULT 0 NOT NULL; UPDATE teacher SET wcf 0 WHERE wcf IS NULL;3.3 视图 WITH CHECK OPTION 缺失INSERT 时“合法”却破坏业务规则现象试卷1第六大题第 4 小题建视图BMV部门为“经管系”但未加WITH CHECK OPTION。之后执行INSERT INTO BMV VALUES (张三, 5000, 8000);成功但查SELECT * FROM teacher发现该记录部门为NULL或其他值。原因视图只是查询封装INSERT实际写入基表。若视图条件为WHERE bm经管系但未加WITH CHECK OPTION数据库不校验新行是否满足bm经管系。解决-- ✅ 必须加上 WITH CHECK OPTION CREATE VIEW BMV AS SELECT XM, JBGZ, SFGZ FROM teacher WHERE bm 经管系 WITH CHECK OPTION; -- 关键 -- 测试以下 INSERT 将失败因 bm 不是 经管系 INSERT INTO BMV VALUES (李四, 6000, 9000);3.4 子查询中的 NULL 处理IN/NOT IN 与 EXISTS 的语义鸿沟现象试卷1第七大题第 2 小题SELECT 成绩 FROM 选课 WHERE 学号 IN (SELECT 学号 FROM 学生 WHERE 姓名 LIKE 李%)当学生表中学号有NULL时结果为空。原因IN子句遇到NULL会返回UNKNOWN导致整个条件失效三值逻辑。而EXISTS只关心是否存在匹配行不受NULL影响。解决-- ❌ 危险IN 遇 NULL 失效 SELECT score FROM sc WHERE sno IN (SELECT sno FROM student WHERE sname LIKE 李%); -- ✅ 安全用 EXISTS 替代 SELECT score FROM sc s WHERE EXISTS ( SELECT 1 FROM student st WHERE st.sno s.sno AND st.sname LIKE 李% ); -- 或显式过滤 NULL SELECT score FROM sc WHERE sno IN ( SELECT sno FROM student WHERE sname LIKE 李% AND sno IS NOT NULL );3.5 DROP TABLE 的级联风险删表前没查外键依赖现象试卷1第六大题第 5 小题DROP TABLE teacher;在有外键引用的库中执行失败报错Cannot delete or update a parent row: a foreign key constraint fails。原因teacher表被其他表如salary_log的外键引用MySQL 默认禁止删除。解决-- 1. 先查依赖关系MySQL 8.0 SELECT CONSTRAINT_NAME, TABLE_NAME, COLUMN_NAME, REFERENCED_TABLE_NAME, REFERENCED_COLUMN_NAME FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE REFERENCED_TABLE_NAME teacher; -- 2. 临时禁用外键检查仅开发环境 SET FOREIGN_KEY_CHECKS 0; DROP TABLE teacher; SET FOREIGN_KEY_CHECKS 1; -- 3. 生产环境正确做法先删子表再删父表 DROP TABLE salary_log; -- 假设这是引用 teacher 的表 DROP TABLE teacher;4. 关系代数到 SQL除法运算的三种落地姿势与性能边界试卷1第五大题第 4、5 小题和试卷2第五大题第 4 小题核心都是关系代数中的除法运算Division求“选修了全部课程的学生”。这是数据库理论中最易混淆的操作也是 SQL 实现时性能差异最大的场景之一。很多人死记硬背NOT EXISTS嵌套却不知其背后的执行计划代价。下面给出三种可落地的方案并标注适用规模。4.1 标准解法双重 NOT EXISTS理论严谨中小表首选这是教材和试题的标准答案逻辑清晰符合关系代数定义。-- 求选修了全部课程的学生学号和姓名 SELECT s.sno, s.sname FROM student s WHERE NOT EXISTS ( -- 找出一门课程 c该学生 s 没选修 SELECT 1 FROM course c WHERE NOT EXISTS ( -- 检查学生 s 是否选修了课程 c SELECT 1 FROM sc WHERE sc.sno s.sno AND sc.cno c.cno ) );逻辑说明外层NOT EXISTS表示“不存在这样的课程 c”内层NOT EXISTS表示“学生 s 没选 c”。双重否定即“对所有课程 c学生 s 都选了”。参数说明sc表需在(sno, cno)上有联合索引否则内层子查询会全表扫描sc表复杂度 O(n×m×k)n学生数m课程数k选课记录数。4.2 优化解法GROUP BY HAVING COUNT大数据量友好当课程数固定如全校 200 门课且sc表有(sno, cno)索引时此法性能远超双重嵌套。-- 假设 course 表共 200 门课 SELECT s.sno, s.sname FROM student s JOIN sc ON s.sno sc.sno GROUP BY s.sno, s.sname HAVING COUNT(DISTINCT sc.cno) 200; -- ✅ 直接比数量优势只需一次sc表扫描GROUP BY在索引支持下是高效聚合。注意COUNT(DISTINCT sc.cno)必须与课程总数严格相等若课程表动态增减需用子查询获取实时总数HAVING COUNT(DISTINCT sc.cno) (SELECT COUNT(*) FROM course)4.3 工程解法预计算选课向量超大规模场景当学生数超百万、课程数超千门时上述两种方法仍可能慢。此时应跳出 SQL 思维用应用层预计算。# Python 伪代码用位图压缩选课状态 from bitarray import bitarray # 1. 初始化课程ID到bit位置的映射课程ID需连续或哈希后映射 course_to_bit {cno: i for i, cno in enumerate(course_ids)} # course_ids 来自 SELECT cno FROM course # 2. 对每个学生生成选课位图 student_bitmaps {} for sno, cno_list in student_courses.items(): # student_courses: {sno: [cno1, cno2, ...]} bitmap bitarray(len(course_ids)) bitmap.setall(0) for cno in cno_list: if cno in course_to_bit: bitmap[course_to_bit[cno]] 1 student_bitmaps[sno] bitmap # 3. 全1位图即选修全部课程 full_bitmap bitarray(len(course_ids)) full_bitmap.setall(1) full_students [sno for sno, bm in student_bitmaps.items() if bm full_bitmap]适用场景实时性要求不高如T1报表、课程集合稳定。内存占用 学生数 × (课程数/8) 字节100万学生、1000门课仅需 ~125MB 内存。对比SQLNOT EXISTS在同样数据量下执行时间可能达分钟级。5. 数据库保护实战ACID 如何在事务中“肉眼可见”地失效试卷1CH5 和试卷2第四大题第 4 小题都在考 ACID 特性但真正有价值的不是背诵定义而是理解它们在事务执行中如何被打破、又如何被修复。我曾在线上环境亲眼见过一个UPDATE语句因隔离级别设置错误导致财务系统出现“幽灵扣款”——钱扣了两次日志却只记一次。下面用中南试题的典型场景还原 ACID 的“肉眼可见”时刻。5.1 原子性AtomicityROLLBACK 不是魔法是日志的精确回放现象试卷1第七大题第 7 小题INSERT INTO 学生 VALUES(99001,张强,男,22,经管系);执行后因磁盘满导致写入失败但部分字段已落盘。原因原子性依赖WALWrite-Ahead Logging。InnoDB 中事务开始时先写 redo log重做日志再修改 buffer pool若崩溃重启时用 redo log 恢复未刷盘的修改。但若 redo log 本身写失败如磁盘满则事务无法保证原子性。验证方法-- 1. 查看当前事务日志状态 SHOW ENGINE INNODB STATUS\G -- 2. 检查 redo log 文件大小避免写满 SELECT FILE_NAME, FILE_SIZE, MAX_SIZE FROM INFORMATION_SCHEMA.FILES WHERE FILE_TYPE LOGFILE; -- 3. 关键参数innodb_log_file_size 应 256M生产环境 SHOW VARIABLES LIKE innodb_log_file_size;教训原子性不是绝对的。当innodb_log_file_size过小如默认 48M高并发写入时 redo log 循环覆盖过快可能导致部分事务日志丢失。从那以后我每次部署新库都强制走一遍innodb_log_file_size 1G的调优流程。5.2 一致性Consistency约束检查的时机决定数据“真假”现象试卷1第七大题第 8 小题UPDATE 学生 SET 学号99089 WHERE 学号95001;执行后发现95001记录消失但99089未出现。原因一致性由约束Constraint 触发器Trigger 应用逻辑共同保障。若学号是主键此 UPDATE 本质是 DELETEINSERT。若sc表有外键ON DELETE CASCADE则95001的选课记录被级联删除但若sc表无外键或ON DELETE RESTRICT则 UPDATE 因外键冲突失败事务回滚——但应用层若没捕获异常就会误以为“没执行”。验证方法-- 1. 查外键定义确认级联行为 SELECT CONSTRAINT_NAME, UPDATE_RULE, DELETE_RULE FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE kcu JOIN INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS rc ON kcu.CONSTRAINT_NAME rc.CONSTRAINT_NAME WHERE kcu.TABLE_NAME sc AND kcu.COLUMN_NAME sno; -- 2. 强制开启外键检查避免被禁用 SET FOREIGN_KEY_CHECKS 1;5.3 隔离性IsolationREAD COMMITTED 下的“不可重复读”现场复现试卷2第二大题第 7 小题问“DBMS 中实现事务隔离性的子系统”答案是并发控制子系统。但真正重要的是不同隔离级别下同一 SQL 执行两次结果为何不同复现步骤MySQL-- 会话 A设置 READ COMMITTED SET TRANSACTION ISOLATION LEVEL READ COMMITTED; START TRANSACTION; SELECT score FROM sc WHERE sno 95001 AND cno 1; -- 返回 85 -- 会话 B同时执行 START TRANSACTION; UPDATE sc SET score 95 WHERE sno 95001 AND cno 1; COMMIT; -- 会话 A 再执行 SELECT score FROM sc WHERE sno 95001 AND cno 1; -- 返回 95即“不可重复读”原因READ COMMITTED 级别下每次 SELECT 都建立新快照会看到其他已提交事务的修改。若需“可重复读”必须用REPEATABLE READMySQL 默认它在事务开始时创建一致性快照。5.4 持久性Durabilitysync_binlog1 不是银弹fsync 才是命门现象数据库崩溃后INSERT语句显示成功但重启后数据丢失。原因持久性依赖binlog redo log fsync三重保障。若sync_binlog0默认binlog 可能未刷盘若innodb_flush_log_at_trx_commit0redo log 也未刷盘。安全配置生产环境必设-- MySQL 配置文件 my.cnf [mysqld] sync_binlog 1 # 每次事务提交都刷 binlog 到磁盘 innodb_flush_log_at_trx_commit 1 # 每次事务提交都刷 redo log 到磁盘 innodb_doublewrite ON # 开启双写缓冲防页损坏注意innodb_flush_log_at_trx_commit1会降低写入性能但这是持久性的底线。从那以后我每次上线新服务都强制用mysqlslap压测写入性能确保在1配置下 QPS 仍满足 SLA。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?
咨询建站