尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

数据库系统原理全真模拟三:事务并发与范式分解核心考点精讲

数据库系统原理全真模拟三:事务并发与范式分解核心考点精讲 数据库系统原理全真模拟演练三来了。前两套发完之后一直有读者在后台问我“事务并发和恢复这块到底怎么练”“范式题有没有更系统的拆解方法”所以这一套我直接把命题重心压在了事务与并发控制、日志恢复、范式理论、SQL与关系代数设计这几个板块上。这套题的定位很明确面向期末冲刺、考研专业课复习以及想系统检验自己对数据库原理掌握程度的人。题型分布参考了主流高校的期末卷和考研真题风格没有偏题怪题但每一道都埋了至少一个容易失分的点做完之后建议对着解析部分逐条核对特别是“为什么选这个而不选那个”的逻辑。1. 这套模拟题的总体设计与考点分布1.1 为什么把这几个板块作为命题重心数据库系统原理这门课不同学校用的教材可能不一样但命题的大头非常集中事务与并发、日志恢复、范式理论、SQL与关系代数、索引与查询优化。这五个板块基本占了一份试卷的70%以上而且也是学生最容易“学了后面忘前面”的部分。先说事务与并发控制。这块几乎是每年必考的大题来源两段锁协议、可串行化判断、隔离级别、死锁处理这些知识点既容易出选择题也容易和日志恢复结合出综合题。很多同学背了概念但不会做题尤其是给你一个具体调度让你判断是否冲突可串行化第一步冲突对的枚举就经常漏。再说范式理论。这块属于“公式简单但应用容易翻车”的典型。判定部分依赖、传递依赖判断最高属于第几范式以及无损分解和保持依赖的分解每一步都有细节。很多同学在“R满足3NF还是BCNF”这个问题上卡住本质上是没有严格对照定义去验证每一个函数依赖。日志恢复和查询设计属于实操性很强的考点。日志恢复需要理解REDO和UNDO的判定逻辑而SQL与关系代数的设计题则是直接考查动手能力。我见过太多人理论背得滚瓜烂熟一写SQL就语法错误或者关系代数写出来的表达式逻辑上不等价。1.2 题型结构与难度梯度这套模拟题共设计了四种题型对应的分值和难度定位如下题型题量建议分值难度定位考查重点选择题8每题2分基础到中等概念辨析、原理理解、特性判断填空题6每题2分基础术语准确性、细节记忆简答与设计题4共20分中等到偏难协议描述、SQL与关系代数书写综合题2共30分难调度判断与范式分解的完整推导从难度设计上看选择题不是单纯送分而是通过“最准确的说法”“错误的是”这类问法制造区分度。填空题抠的是术语细节比如“一级封锁协议的释放时机”。综合题则要求完整的推导过程只有答案没有步骤在实际阅卷中是要扣过程分的。这套题整体比前两套更偏“原理深度”适合在复习完一轮之后用来自测。2. 客观题精讲选择与填空的底层逻辑2.1 选择题解析选项背后的原理比对第一题一个事务执行到一半发生系统故障系统重启后该事务被强制撤销这体现了事务的哪个特性A. 原子性 B. 一致性 C. 隔离性 D. 持久性正确答案是A。这个题的干扰项主要是一致性。一致性和原子性的关系是这样的一致性是事务执行前后的整体状态约束而原子性是“要么全做、要么全不做”的执行语义。事务执行到一半故障部分写入已经落盘此时撤销这个事务本质是保证它不会在数据库中留下中间状态所以这是原子性的体现。如果题目问的是“多个事务并发执行互不干扰”那才选隔离性。第二题在SQL标准中隔离级别由弱到强的正确排序是A. Read Uncommitted Read Committed Repeatable Read Serializable B. Read Committed Read Uncommitted Repeatable Read Serializable C. Serializable Repeatable Read Read Committed Read Uncommitted D. Read Uncommitted Repeatable Read Read Committed Serializable正确答案是A。这个题本身不难但有一个延伸考点值得注意理论的隔离级别排序和具体数据库的默认配置并不一定一致。比如MySQL的InnoDB默认隔离级别是Repeatable Read而Oracle默认是Read Committed。考试喜欢考标准排序实际工程中则要清楚自己用的数据库默认处于哪个隔离级别这直接影响并发时的数据一致性表现。第三题关于两段锁协议下列说法错误的是A. 所有事务的加锁和解锁分为扩展阶段和收缩阶段 B. 两段锁协议能保证冲突可串行化 C. 两段锁协议一定能避免死锁 D. 严格两段锁协议要求事务在提交后才能释放所有锁正确答案是C。两段锁协议确实能保证冲突可串行化但它不避免死锁。因为两个事务可能各自持有部分锁、又同时申请对方持有的锁形成循环等待。死锁在2PL下依然可能发生所以数据库系统还需要死锁检测、死锁预防或超时机制来处理。这个选项迷惑性极强很多同学默认“加锁协议和死锁有关那一定可以避免死锁”实际上两者没有必然的因果关系。第四题多版本并发控制MVCC相比传统基于封锁的并发控制最主要的特点是A. 读操作通常不加锁且不会阻塞写操作 B. 可以完全避免事务回滚 C. 不再需要日志 D. 彻底解决了写冲突正确答案是A。MVCC的核心思想是让读操作通过快照读来实现不加锁的读从而做到读不阻塞写、写不阻塞读。但要注意MVCC并不能完全避免回滚写冲突仍然需要处理事务的回滚机制依然依赖日志所以B和C都不对。D更离谱写冲突在MVCC下依然存在只是处理方式从阻塞变成了版本比较。第五题关于B树索引下列说法正确的是A. 非叶子节点存储实际数据 B. 叶子节点通过链表连接支持高效的范围查询 C. 插入和删除过程中绝对不会发生页分裂 D. 只适合等值查询不适合范围查询正确答案是B。B树区别于B树最明显的一点就是非叶子节点只存键和指针实际数据全部在叶子节点并且叶子节点之间用链表串联。这个设计带来的直接好处就是范围查询非常高效只要定位到范围的起点顺着链表往后扫就可以。A和D的说法正好和事实相反。C过于绝对页分裂在插入过程中是正常现象B树通过分裂和调整保持平衡。第六题基于代价的查询优化器下列哪一项不是其工作内容A. 收集和维护统计信息 B. 对查询表达式进行等价变换 C. 生成多个候选执行计划并估算代价 D. 实际执行查询并直接返回结果正确答案是D。优化器的任务是“选计划”而不是“执行计划”。它通过直方图等统计信息估算各个操作符的基数、IO代价和CPU代价再挑选代价最小的执行计划。实际执行是执行引擎的事。这个题提醒大家优化器是静态分析阶段不要和执行阶段混在一起。第七题关系模式R(A,B,C)函数依赖集F{A→B, B→C}则R最高满足第几范式A. 1NF B. 2NF C. 3NF D. BCNF正确答案是B。这里的判断过程要严谨。候选码只有A。非主属性是B和C。A→B是主属性直接决定非主属性没有部分依赖的问题但是B→C意味着C通过B传递依赖于A因此R不满足3NF。2NF只需要消除非主属性对码的部分函数依赖这里B和C都完全依赖于A所以满足2NF。这个题的关键是分清“完全依赖”和“传递依赖”分别影响的是第几范式。第八题数据库系统中设置检查点checkpoint的主要目的是A. 定期备份数据库 B. 减少系统故障恢复时需要扫描和处理的日志量 C. 保证事务的自动提交 D. 防止磁盘介质损坏正确答案是B。检查点机制会把内存中已提交的数据强制写入磁盘并在日志中记录检查点信息。故障恢复时只需要从最近一个检查点开始扫描日志检查点之前已提交事务的REDO记录可以不再处理从而缩短恢复时间。A和D属于备份与容灾范畴和检查点不是一回事。2.2 填空题解析术语准确性与易错点提醒第一题事务的四个特性是原子性、____、隔离性、持久性简称为ACID。答案是“一致性”。这个题单纯考记忆但需要强调ACID中每个特性的英文对应Atomicity、Consistency、Isolation、Durability。第二题一级封锁协议要求事务在修改数据之前必须先加____并且要等事务结束后才释放。答案是“排他锁X锁”。注意区分一级封锁协议解决的是“丢失修改”问题它的锁持有方式是“修改前加X锁直到事务结束”。如果题目改成“二级封锁协议”则是在一级的基础上增加“读之前加S锁读后即可释放”用来解决脏读。第三题关系代数中选择运算的符号是____投影运算的符号是____。答案是“σsigma、πpi”。这里最容易写错的是选择与投影的先后顺序。实际写表达式时要记住先用选择缩小行再用投影抽取列效率更高也更容易保证语义正确。第四题若关系模式中存在非主属性对候选码的部分函数依赖则它至少属于____范式要消除这种依赖需要将其分解到____范式。答案是“1NF、2NF”。这个题的隐含考点是“分解到第几范式”的表述。很多同学会用“满足2NF”来描述目标更严格地说是“消除部分函数依赖使其达到2NF”。第五题日志文件中的每条日志记录通常包含事务标识、、数据项更新前的值、。答案是“操作类型与数据项标识、更新后的值”。日志记录的内容是为了支持UNDO和REDO所以必须同时保留旧值和新值。缺了旧值事务回滚时就不知道改回什么缺了新值重做时就不知道改成什么。第六题在SQL中创建视图的语句是____撤销视图的语句是____。答案是“CREATE VIEW、DROP VIEW”。这是一个送分题但偶尔会考“视图修改”的规则比如对包含聚合函数的视图通常不能直接通过视图执行INSERT或UPDATE操作这点值得连带复习。3. 简答与设计题怎么答才不丢分3.1 两段锁协议与日志恢复的答题要点简答题第一问请简述两段锁协议的内容并说明为什么两阶段加锁能保证冲突可串行化。这个题在阅卷时看三个得分点定义、扩展阶段和收缩阶段的划分、可串行化的原因。参考答案可以这样组织两段锁协议要求每个事务分成两个阶段进行加锁和解锁。扩展阶段事务只能获得锁不能释放锁。收缩阶段事务只能释放锁不能获得新锁。也就是说一旦事务开始释放第一个锁就正式进入收缩阶段之后不能再加任何锁。为什么能保证冲突可串行化直观理解是任意两个事务的冲突操作的执行顺序在提交之前的加锁顺序已经被固定下来。假设事务T1和T2存在冲突操作那么后获得锁的事务一定是在先获得锁的事务完成解锁之后才拿到锁这等价于在某个串行调度中顺序执行。需要额外强调的是两段锁协议保证的是“冲突可串行化”而不是“视图可串行化”或“完全避免死锁”。严格两段锁协议还要加上一条事务的所有锁在提交或回滚时才统一释放这样可以进一步避免级联回滚。简答题第二问简述基于日志的REDO和UNDO操作的判定规则。答这个题的关键是把“提交”和“刷盘”分开讨论。系统故障恢复时从日志尾部向前扫描对每条日志记录判断如果某个事务的日志中包含提交记录COMMIT但它修改的数据在故障前可能没有全部写入磁盘则对该事务执行REDO重做所有更新操作保证持久性。如果某个事务的日志中没有提交记录说明事务并没有成功完成则对该事务执行UNDO把数据恢复为更新前的值保证原子性。判据可以简化成有提交记录就REDO没有提交记录就UNDO。但如果考试中提到“检查点”还要补充检查点之前已经提交的事务如果其数据已经在检查点写入磁盘则无需再REDO这是检查点缩短恢复时间的关键。3.2 SQL与关系代数设计题的等价转换思路设计题给出了经典的学生-课程-选课场景S(Sno, Sname, Sdept)、C(Cno, Cname, Ccredit)、SC(Sno, Cno, Grade)。第一小问用关系代数查询“选了‘数据库’课程的学生姓名”。正确的表达式涉及选择、连接、投影三步π Sname( σ Cname数据库( S ⋈ SC ⋈ C ) )这里最容易出错的是连接条件漏写直接把三个关系做了笛卡尔积。正确的做法是先通过自然连接或显式连接条件把三个表关联起来再用选择过滤课程名最后投影出姓名。关系代数中自然连接会自动消除重复属性但如果教材采用θ连接表示法必须写清楚连接条件“S.SnoSC.Sno AND SC.CnoC.Cno”。第二小问查询“平均成绩大于80分的学号”关系代数表示π Sno( σ avg_grade 80 ( Sno G avg(Grade) (SC) ) )这里用到的是分组聚合运算用G表示分组。实际在SQL中对应的是GROUP BY和HAVING的组合代码为SELECT Sno FROM SC GROUP BY Sno HAVING AVG(Grade) 80;HAVING和WHERE的过滤时机差异是经典易错点。WHERE在分组之前过滤行HAVING在分组之后过滤组。如果把上面的条件误写成WHERE AVG(Grade) 80SQL会因为聚合函数不能直接出现在WHERE中而报错。第三小问是“查询至少选修了学生‘2023001’所选全部课程的学生学号”也就是典型的除法运算。关系代数用除法π Sno,Cno(SC) ÷ π Cno( σ Sno2023001(SC) )SQL标准中除法没有直接的关键字通常用NOT EXISTS双重否定实现SELECT DISTINCT Sno FROM SC S1 WHERE NOT EXISTS ( SELECT 1 FROM SC S2 WHERE S2.Sno 2023001 AND NOT EXISTS ( SELECT 1 FROM SC S3 WHERE S3.Sno S1.Sno AND S3.Cno S2.Cno ) );这个题每年都有不少同学理解不了“至少选修全部课程”和“NOT EXISTS嵌套”之间的关系。换成人话就是不存在这么一门课它被2023001选了但没被当前这个学生选。内层NOT EXISTS判断“当前学生是否漏选了某门课”外层NOT EXISTS判断“是否存在漏选的情况”两层取反之后就变成了“当前学生没有漏选任何一门课”逻辑正好等价于“选了全部课程”。第四小问要求用SQL查询每门课程最高分对应的学生姓名。这里给出一种使用窗口函数的写法SELECT Cname, Sname, Grade FROM ( SELECT C.Cname, S.Sname, SC.Grade, RANK() OVER (PARTITION BY SC.Cno ORDER BY SC.Grade DESC) AS rk FROM SC JOIN C ON SC.Cno C.Cno JOIN S ON SC.Sno S.Sno ) t WHERE rk 1;窗口函数PARTITION BY按课程分组ORDER BY按成绩排序RANK()为每组内生成名次。如果每门课有多个并列最高分RANK会返回多个第1名。如果要求严格唯一可以换成ROW_NUMBER()。窗口函数是SQL进阶考察的重点也是很多学校期末题和面试题喜欢涉及的方向。4. 综合题命题方向与完整推导4.1 一个完整的事务调度判断过程综合题给了一个典型的两事务调度要求判断它是否冲突可串行化。事务T1执行的操作序列read(A)AA-100write(A)read(B)BB100write(B)。事务T2执行的操作序列read(A)AA2write(A)read(B)BB2write(B)。调度S如下S: r1(A), r2(A), w1(A), w2(A), r2(B), w2(B), r1(B), w1(B)第一步找出所有冲突操作对。两个操作冲突的条件是来自不同事务、作用于同一数据项、且至少有一个是写操作。按数据项A看有这些冲突对r1(A)与w2(A)顺序为1在4之前所以T1→T2r2(A)与w1(A)顺序为2在3之前所以T2→T1w1(A)与w2(A)顺序为3在4之前所以T1→T2。再看数据项Br2(B)在r1(B)之前但read-read不冲突r2(B)与w1(B)顺序为5在8之前所以T2→T1w2(B)与r1(B)顺序为6在7之前所以T2→T1w2(B)与w1(B)顺序为6在8之前所以T2→T1。第二步画出优先图。节点是T1和T2边分别有T1→T2和T2→T1形成环。因此调度S不是冲突可串行化的。这个题想提醒两件事。第一冲突对的枚举不能凭直觉要按数据项逐个检查尤其是read(A)与其他事务write(A)之间的冲突经常被遗漏。第二优先图中只要出现环就不存在等价于该调度执行顺序的串行调度。如果题目进一步问“如何修改成等价串行调度”常见的做法是调整冲突操作的相对顺序比如让T1完整执行完再执行T2调度变为r1(A), w1(A), r1(B), w1(B), r2(A), w2(A), r2(B), w2(B)此时优先图无环等价于串行调度T1→T2。4.2 一个逐步拆分到BCNF的规范化综合题综合题第二问给了一个典型的关系模式R(U,F)其中属性包括学号Sno、系名Sdept、系主任Dean、课程号Cno、成绩Grade。函数依赖集F{Sno→Sdept, Sdept→Dean, (Sno,Cno)→Grade}。第一步求候选码。能决定所有属性的最小属性集是(Sno,Cno)。验证一下Sno能推出SdeptSdept能推出DeanSno和Cno一起能推出Grade所以(Sno,Cno)确实能推出全部五个属性。去掉Sno或Cno都无法推出全部属性因此候选码是(Sno,Cno)。第二步判断当前范式。非主属性有Sdept、Dean、Grade。观察函数依赖(Sno,Cno)→Sdept这个依赖的左边包含了候选码的真子集Sno而且Sdept可以通过Sno独立推出所以存在非主属性对候选码的部分函数依赖。部分依赖意味着R不满足2NF目前只满足1NF。第三步分解到2NF。分解的基本原则是“让每个关系模式内部不再存在部分依赖”。把与Sno直接相关的属性Sdept和Dean抽出去和Sno组成R1(Sno,Sdept,Dean)再把(Sno,Cno)→Grade保留在R2(Sno,Cno,Grade)中。检查R2候选码是(Sno,Cno)非主属性只有Grade不存在部分依赖满足2NF。检查R1候选码是Sno非主属性Sdept和Dean都完全依赖于Sno满足2NF。第四步继续分解到3NF。观察R1Sno→SdeptSdept→Dean这里存在传递依赖。3NF要求消除非主属性对候选码的传递依赖。分解R1为R11(Sno,Sdept)和R12(Sdept,Dean)。R11中候选码SnoSno→Sdept是直接依赖R12中候选码SdeptSdept→Dean是直接依赖。此时三个关系模式都不存在传递依赖满足3NF。第五步判断是否也满足BCNF。BCNF的要求更严格要求每个非平凡函数依赖的左边都必须是超码。检查R2函数依赖(Sno,Cno)→Grade左边是候选码BCNF成立。检查R11Sno→SdeptSno是超码BCNF成立。检查R12Sdept→DeanSdept是超码BCNF成立。所以这个分解同时也满足BCNF。无损性和保持函数依赖也是综合题的高频问法。这个分解中R2与R11通过Sno连接可以重新得到原关系R11与R12通过Sdept连接也能恢复出Dean信息分解是无损的。函数依赖方面F中的三个依赖分别落在R2、R11、R12中没有丢失因此分解保持函数依赖。这个题给我个人的教学感触很深。很多同学会跳过前面的范式判定直接写最终分解但阅卷是按步骤给分的尤其是“最高满足第几范式”的判定过程和每一步分解的依据占的分值比重相当高。5. 易错点、判卷标准与复习建议5.1 反复出现的五个失分点第一个失分点是范式判定的混淆。部分函数依赖对应2NF传递函数依赖对应3NFBCNF要求所有函数依赖左边都是超码。很多人记住“3NF消除传递依赖”但遇到MVD等相关概念时又开始混。复习时用一组小例子把每个范式的判定条件刻在脑子里1NF讲属性原子性2NF讲消除部分依赖3NF讲消除传递依赖BCNF讲所有决定因素都是超码。第二个失分点是SQL与关系代数的逻辑不等价。典型表现是关系代数写出来的表达式结果集和SQL查出来的结果集不一样。常见原因包括没有处理重复元组的去重、自然连接和θ连接混用、除法查询用错NOT EXISTS嵌套层级。遇到这类问题建议每一步操作都手动模拟一遍小数据确认结果集一致。第三个失分点是两段锁协议与死锁的关系。反复强调一遍2PL保证冲突可串行化但既不避免死锁也不避免级联回滚。只有严格两段锁协议所有锁在事务结束时统一释放才能避免级联回滚而避免死锁需要死锁预防协议或死锁检测机制。这是简答题最常考察的区分点。第四个失分点是日志恢复时REDO与UNDO的误判。简化规则是“看事务有没有COMMIT日志记录”。有COMMIT就REDO没有就UNDO。带检查点时检查点之前已提交且数据已落盘的事务可以跳过。实际做题时建议先画一条时间线标出事务开始、检查点、故障点再逐个事务判断。第五个失分点是事务隔离级别与锁协议的对应关系不清。SERIALIZABLE不一定非要通过2PL实现也可以通过时间戳、MVCC或其他机制实现。考试如果问“哪些隔离级别可能产生幻读”要记得Read Uncommitted和Read Committed会产生不可重复读和幻读Repeatable Read在标准定义下仍可能产生幻读只有Serializable能完全避免。但MySQL的InnoDB通过间隙锁在Repeatable Read下也解决了幻读这个工程特例经常被单独拿出来出选择题。5.2 这套题的后续用法做完这套题之后我建议不要只看对错而是把每个错题对应的知识点回到教材目录里定位。如果选择题第7题出错说明范式理论部分对“部分依赖”和“传递依赖”的分辨还不够如果综合题第4.1节出错说明调度分析中冲突对枚举和优先图构建需要专项练习。可以试着把错题改编成新的题目比如换一组数据项、换一个调度顺序再做一遍。真题模拟和章节练习最大的区别在于综合度。章节练习每一章的知识点是固定搭好的模拟题则要求你自己判断该用哪一章的工具去解题。这恰好是考试真正考察的能力。我个人在实际教学中发现数据库系统原理这个科目最有效的复习节奏是“两轮真题模拟加一轮错题重做”。第一轮模拟用来暴露问题第二轮模拟用来验证问题是否解决错题重做则用来巩固那些最细碎、最容易反复出错的知识点。这套全真模拟演练三的核心目的就是帮你把那些平时不太起眼但考试特别能拉分的细节暴露出来。把这些细节一个个补牢比你盲目刷三遍教材目录有用得多。
返回列表