数据库这门课,期末复习跟其它科目完全不是一个套路。它既有理论得像数学的部分,又有实操得像编程的部分,还得背一堆概念,很多同学复习到后面就是“理论忘光了,SQL写不利索,范式判断全靠蒙”。这份期末复习笔记,就是针对这种情况整理的,围绕关系模型、SQL、范式、事务这些核心考点,把课本里分散的知识点串成几条清晰的复习主线,配合例题和实战演示,帮你把零散的内容真正吃透。不管你是考前突击,还是平时学得模棱两可想系统过一遍,这份笔记都能直接拿来用。
我当年复习的时候,最大的感受就是:数据库的考点非常固定,翻来覆去就那几类。你只要按题型去拆解,按知识点去归纳,把“为什么这么考”想明白了,拿分并不难。下面我把整门课的复习思路、核心细节、实操演示、常见扣分点完整拆开讲。
1. 复习的整体思路与考点分布
为什么数据库期末复习容易让人抓狂?因为这门课的体系太杂了。你看目录,前面讲关系模型、关系代数、SQL,中间讲范式、数据库设计,后面又跳到事务、并发控制、索引、存储,感觉每一章都是独立的,合在一起又不知道谁先谁后。
但你换个角度看,整门课其实就是在回答一个问题:怎么把现实世界的数据,可靠、高效地存进计算机,并且随时能查出来用。整个知识体系是围绕这个目标层层展开的。你按这个逻辑去复习,思路就顺了。
1.1 三条主线串起整门课
我把整门课的内容拆成三条主线,复习时按线走,比按章节走高效得多:
第一条线:数据怎么组织和描述。从现实世界到概念模型,再到逻辑模型。重点就是实体联系图(ER图)和关系模型。ER图解决的是“现实世界的东西怎么抽象成实体和联系”,关系模型解决的是“抽象出来的东西怎么用二维表表示”。这一线对应考试里的设计题,通常是让你画ER图、转关系模式,偶尔会让你判断某张表设计得合不合理。
第二条线:数据怎么查和改。这就是SQL的主场。关系代数是理论基础,SQL是具体实现。考试里的SQL题基本覆盖查询、插入、删除、更新、视图、授权,其中查询是绝对的大头,尤其是连接查询、嵌套查询、分组统计这些组合拳。这一线属于“会就是会,不会就是不会”,没有半点模糊空间,复习到位了就是送分题。
第三条线:数据怎么保证正确和安全。这就是约束、范式、事务、并发控制和恢复。范式解决的是“表设计得不好会怎么样”,事务和并发控制解决的是“多个用户同时操作数据会不会出乱子”,恢复解决的是“系统崩了数据怎么找回来”。这一线对应简答题、分析题和设计题,也是整套试卷里区分度最高的部分。
你对照教材目录看,会发现所有章节都能归到这三条线里。复习的时候,先把每一条线里的知识点列出来,标出重点,再按线去刷题,会清晰很多。
1.2 考点权重与命题规律
结合课程重点和期末试卷的出题惯性,各模块的权重大致如下:
| 知识模块 | 常见考查形式 | 大致权重 | 复习优先级 |
|---|---|---|---|
| 关系模型与关系代数 | 选择、填空、简答 | 10%-15% | 必须拿稳 |
| SQL语言 | 上机题、大题 | 25%-35% | 绝对核心 |
| 数据库设计(ER图+范式) | 设计大题、分析题 | 15%-25% | 必须拿稳 |
| 事务与并发控制 | 简答、分析题 | 10%-15% | 拉分关键 |
| 数据库恢复技术 | 选择、简答 | 5%-10% | 理解为主 |
| 索引与查询优化 | 选择、填空 | 5%-10% | 记住原理 |
| 数据库安全与完整性 | 选择、简答 | 5%左右 | 背概念为主 |
你发现没有,SQL和数据库设计加起来占了半壁江山。这两块又是最吃熟练度的,光看笔记不写不练,上考场一定会手生。所以复习策略一定要倾向这两个模块多投入时间。
1.3 复习资料的取舍
期末复习最怕资料太多,每个文件都看几页,结果哪本都没吃透。我的建议是只盯住三层资料:
第一层是老师的PPT和平时作业。这层直接对着考点,把PPT上的例题搞懂,作业里的错题重做一遍,比看十本参考书都有用。尤其是老师反复强调过的内容,大概率就是期末的重点。
第二层是教材。教材的作用是查漏补缺,不是通读。当你发现某个概念PPT上没讲透,或者例题没有覆盖,再去翻教材对应章节,把原理弄明白。
第三层是往年真题或模拟题。这一层用来熟悉题型和练手速。你至少要在考试前完整做两套卷子,一套不限时,看自己哪里不会;一套限时,模拟真实考场节奏。做完之后把错题对应的知识点回扣到前两层资料里,形成“做题—找漏—补漏”的闭环。
我当时就是这样,先花一个晚上把知识点按三条线过了一遍,再花两个晚上刷题,最后一天集中看错题和背诵概念。整个过程紧凑但不慌乱,比漫无目的地从第一章翻到最后一章效率高得多。
2. 核心知识点拆解:关系模型与SQL
关系模型是整个数据库课程的基石,SQL是日常用得最多的语言。这两个模块连在一起复习,原因是它们本质上是同一件事的两种形态:关系模型告诉你“数据应该长什么样”,SQL告诉你“怎么把这样的数据拿出来”。
2.1 关系模型的基本概念
关系模型里几个基础概念必须一字不差地记住,因为选择题和填空题就爱在这些地方设坑:
关系(Relation):就是一张二维表。但要注意,关系模型里的“关系”有严格限制:每一列都是不可再分的基本数据项,不允许表中套表;每一列必须来自同一个域,也就是同一列的数据类型一致;列的次序和行的次序可以任意交换,不影响语义。很多人栽在“关系就是一维表”这种想当然的表述上,记住,是一张二维表。
元组(Tuple):表中的一行。属性(Attribute):表中的一列。域(Domain):属性取值的集合。分量:元组中的一个属性值。
候选码(Candidate Key):能唯一标识一个元组的最小属性集合。注意“最小”两个字。比如一个表里有(学号,姓名,身份证号),身份证号和学号都能唯一标识一个人,但它们各自就是候选码,用(学号,身份证号)这个组合去当候选码就不成立,因为不是最小的。
主码(Primary Key):从候选码里挑一个出来做为主键。主属性:包含在任何一个候选码中的属性。非主属性:不包含在任何候选码中的属性。外码(Foreign Key):某个属性组,它不是这个表的主码,但它是另一个表的主码,它把这个表和那个表关联起来。
这里有个高频考点:全码(All Key)。当所有属性加起来才是能唯一标识元组的最小集合时,这个关系的码就是全码。典型例子就是一个“学生选课”关系,只有(学号,课程号)两个属性,单个都不行,合起来才行,这就是全码。
基础概念我整理了一个选择题常考的判断表:
| 说法 | 正确/错误 | 原因 |
|---|---|---|
| 关系中的列次序可以交换 | 正确 | 关系模型规定列序无关 |
| 关系中的行次序可以交换 | 正确 | 关系模型规定行序无关 |
| 关系中不允许出现完全相同的两个元组 | 正确 | 关系是集合,集合不允许重复元素 |
| 关系中某一列可以再拆分成多个子列 | 错误 | 属性必须是不可再分的数据项 |
| 候选码可以有多个 | 正确 | 只要满足唯一+极小的属性组都是候选码 |
| 主码可以有多个 | 错误 | 主码是从候选码中选定的,只能有一个 |
2.2 关系代数:别死记符号,要理解运算逻辑
关系代数是SQL的理论基础,它定义了一组运算规则。期末一般不会让你算很复杂的关系代数表达式,但基础运算符号必须认识,尤其是选择(σ)、投影(π)、连接(⋈)、并(∪)、差(−)这几个。
选择(σ)是选行,条件是横向过滤。投影(π)是选列,是纵向过滤。很多同学把这两个搞混,我教你一个记忆方法:选择是筛选符合条件的那些行——你把每一行看成一个整体,要的是满足条件的行;投影是只保留某些列——就像把一张表的多列投影到少数几列上。考试最常见的写法是:先选择再投影,比如查“计算机系学生的学号和姓名”,就先 σ所在系 = '计算机',再 π学号, 姓名。
连接(⋈)是最容易出错的运算。自然连接是等值连接的一种特例,它要求两个关系中公共属性值相等,并且结果中把重复的公共属性列去掉。而等值连接不会去掉重复列。这个区别,简答题常考。
关系代数和SQL之间还有对应关系:查询块转关系代数、关系代数转SQL,都是常见的出题形式。做题的核心思路是先读懂题目要查什么,再分析涉及哪几张表、需要什么连接条件、最后做怎样的过滤和投影。
2.3 SQL的必考点与易混点
SQL部分是拿分大头,我把期末最常考的语法点和易混点挑出来逐一讲。
必考点一:基本查询结构。SELECT、FROM、WHERE、GROUP BY、HAVING、ORDER BY、LIMIT(不同数据库实现有差异,按课程要求来)。执行顺序和书写顺序不一样,这个考试经常以“以下说法正确的是”来考查。SQL的执行顺序是:FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY → LIMIT。理解这个顺序特别重要,因为WHERE和HAVING能用的东西就是由这个顺序决定的。
必考点二:WHERE和HAVING的区别。这是期末第一易混点。WHERE是在分组之前过滤行,不能使用聚合函数;HAVING是在分组之后过滤组,只能与GROUP BY配合使用。比如“查询选课人数超过3人的课程号”,就得先用GROUP BY按课程号分组,再用HAVING COUNT(*) > 3过滤。你要是把HAVING写成WHERE,直接就报错或结果不对。
必考点三:连接查询。内连接、左外连接、右外连接。考试中内连接最常用,写法可以是用逗号加WHERE,也可以用JOIN ON。左外连接的结果里会保留左表中不满足连接条件的行,右表对应位置填NULL。这个语义必须分清,选择题常考“以下哪个查询能查出没选课的学生”。
写连接查询最容易犯的错是漏掉连接条件,导致出现笛卡尔积式的结果。比如查“学生姓名和选课成绩”,如果你只写FROM 学生, 选课不加WHERE条件,结果每个学生跟每个选课记录都会组合一遍,数据量爆炸且结果毫无意义。做题时先数清涉及几张表,再找表与表之间的关联字段,最后确定连接条件,三步走基本不会错。
必考点四:嵌套查询。IN、NOT IN + 子查询用得最多,EXISTS相关子查询也是常客。用IN的子查询会先执行子查询,再用结果集去匹配外层;用EXISTS的子查询是逐行判断,每取外层一行就去执行一次子查询,看是否存在满足条件的行。性能上,数据量大时EXISTS通常优于IN,但考试主要考语义,不深究性能。
必考点五:增删改与视图。INSERT、DELETE、UPDATE的语法简单,但要注意:DELETE是删除行,不是删除表数据之后表结构还在;DROP TABLE才是连表带结构一起删。视图(VIEW)是虚拟表,不实际存储数据,对视图的更新通常有限制,比如含有聚合函数、分组、DISTINCT的视图不允许更新。简答题常考“为什么视图不能随意更新”,标准答法就是视图本质是保存的查询,不存储真实数据。
我复习SQL时用的方法是把每个语法点拆成“一个例子+一个反例”。例子是正确写法,反例是错误写法。你只要把错误写法里暴露的错因想明白,基本就真会了。这个习惯让我在考场上做SQL题特别快。
2.4 SQL专栏实战演示
光讲理论容易飘,我这里用一个选课系统的小例子,把高频SQL考点串起来。现在有三张表:
-- 学生表 CREATE TABLE 学生 ( 学号 CHAR(10) PRIMARY KEY, 姓名 VARCHAR(20), 所在系 VARCHAR(30), 年龄 INT ); -- 课程表 CREATE TABLE 课程 ( 课程号 CHAR(10) PRIMARY KEY, 课程名 VARCHAR(30), 学分 INT ); -- 选课表(中间表,连接学生和课程) CREATE TABLE 选课 ( 学号 CHAR(10), 课程号 CHAR(10), 成绩 DECIMAL(5,2), PRIMARY KEY(学号, 课程号), FOREIGN KEY(学号) REFERENCES 学生(学号), FOREIGN KEY(课程号) REFERENCES 课程(课程号) );题目一:查询“计算机系”学生的学号和姓名。
SELECT 学号, 姓名 FROM 学生 WHERE 所在系 = '计算机';题目二:查询选了“数据库原理”这门课的学生姓名和成绩。
SELECT 学生.姓名, 选课.成绩 FROM 学生 JOIN 选课 ON 学生.学号 = 选课.学号 JOIN 课程 ON 选课.课程号 = 课程.课程号 WHERE 课程.课程名 = '数据库原理';这里要注意,姓名和成绩都在不同表里,必须把三张表关联起来再过滤。我管这种题叫“三表连查”,是期末SQL题的标配难度。
题目三:查询每门课程的平均成绩,只显示平均成绩大于80分的课程号。
SELECT 课程号, AVG(成绩) AS 平均成绩 FROM 选课 GROUP BY 课程号 HAVING AVG(成绩) > 80;题目四:查询没有选任何课程的学生姓名。这是“NOT EXISTS”的经典场景。
SELECT 姓名 FROM 学生 WHERE NOT EXISTS ( SELECT 1 FROM 选课 WHERE 选课.学号 = 学生.学号 );这几条SQL涵盖了连接、分组、子查询、相关子查询四类高频考点。你在复习时不光要会写,还要能说清楚每一步的语义。比如题目三,让你说为什么用HAVING而不用WHERE,你要能回答出来:因为AVG(成绩)是对分组后的组进行过滤,分组前不存在这个聚合值。
3. 理论难点:函数依赖与范式分解
函数依赖和范式理论是数据库课程里公认最难啃的骨头。难在哪里?因为它是纯理论,没有实操场景做支撑,初学者很容易陷入“背定义但不会做题”的尴尬。但期末考试这块的题型很固定,你把判断和分解的套路吃透,反而比SQL更容易拿到满分。
3.1 函数依赖到底是什么
函数依赖(Functional Dependency)可以用大白话解释:在一个表中,如果能确定属性X的值,就一定能确定属性Y的值,那么就说Y函数依赖于X,记作X → Y。
最简单的例子:知道了一个学生的学号,就能确定这个学生的姓名、所在系。所以“学号 → 姓名”,“学号 → 所在系”成立。
这里有一个重要的区分:完全函数依赖和部分函数依赖。在选课表里,(学号,课程号)→ 成绩,这个依赖是“完全函数依赖”,因为成绩需要通过学号和课程号两个属性才能确定,缺一个都不行。而(学号,课程号)→ 姓名,这是“部分函数依赖”,因为只用学号就能确定姓名,课程号多余了。
传递函数依赖更隐蔽:X → Y,Y → Z,且Y不能确定X,那么Z传递依赖于X。比如:学号 → 所在系,所在系 → 系主任,那么“学号 → 系主任”就是传递依赖。传递依赖是造成数据冗余、更新异常的重要根源,也是范式理论要解决的核心问题。
3.2 三范式和BCNF的判断标准
范式的等级是一层套一层的,每个范式都对表的设计提出了更严格的要求。我从下往上讲:
第一范式(1NF):每一个分量必须是不可再分的数据项。说白了,就是表里不能有“表中有表”的情况。比如一个字段里放“篮球、足球、羽毛球”,这就不满足1NF。这个要求是最底线的,数据库中的表默认都要满足1NF。
第二范式(2NF):在满足1NF的基础上,每一个非主属性都必须完全函数依赖于码。也就是说,不能存在非主属性对码的部分函数依赖。比如选课表(学号,课程号,姓名,成绩),码是(学号,课程号),但“姓名”只依赖于学号,不依赖于课程号,这就存在部分函数依赖,不满足2NF。解决办法就是拆表,把学号和姓名拆到学生表。
第三范式(3NF):在满足2NF的基础上,消除非主属性对码的传递函数依赖。每个非主属性都不能间接由码决定。比如员工表(员工号,部门号,部门经理),码是员工号,而部门号 → 部门经理,所以“员工号 → 部门经理”是传递依赖,不满足3NF。解决方法是把部门号和部门经理拆到部门表。
BC范式(BCNF):在满足3NF的基础上,消除主属性对码的部分依赖和传递依赖。BCNF比3NF更严格的地方在于,3NF只管非主属性,BCNF连主属性一起管。
我整理了一张判断表,做题时对着走:
| 范式级别 | 需要消除的问题 | 判断重点 | 典型反例 |
|---|---|---|---|
| 1NF | 属性不可再分 | 是否有嵌套表或复合属性 | 一个字段存多个值 |
| 2NF | 非主属性对码的部分依赖 | 码是否为单个属性,若不是则检查每个非主属性 | 选课表里学号决定姓名 |
| 3NF | 非主属性对码的传递依赖 | 是否存在X→Y→Z的依赖链 | 学号决定系,系决定系主任 |
| BCNF | 主属性对码的部分/传递依赖 | 所有属性是否都完全直接依赖于每个候选码 | 码内部存在冗余依赖 |
3.3 范式分解实操演示
判断表设计满不满足范式只是第一步,期末大题通常还要求你把不满足范式的关系模式分解成满足目标范式的形式。分解要遵循两个原则:保持函数依赖、无损连接性。考试里一般要求分解到3NF或BCNF,我用一个完整例子演示。
假设有一个关系模式:订单(订单号,客户号,客户姓名,商品号,商品名称,数量),函数依赖集合为:订单号 → 客户号,订单号 → 商品号,订单号 → 数量,客户号 → 客户姓名,商品号 → 商品名称。
第一步,找码。从函数依赖看,订单号能决定客户号、客户姓名、商品号、商品名称、数量,所以码是订单号,单个属性组成的码。
第二步,判断范式级别。非主属性是客户号、客户姓名、商品号、商品名称、数量。由于码是单个属性,不存在部分函数依赖,所以满足2NF。但存在传递依赖:订单号 → 客户号 → 客户姓名,以及订单号 → 商品号 → 商品名称,所以不满足3NF。
第三步,分解。把传递依赖链条中的每一段独立拆表。拆成:
- 订单(订单号,客户号,商品号,数量)
- 客户(客户号,客户姓名)
- 商品(商品号,商品名称)
分解后每个关系模式的非主属性都不存在对码的传递依赖,满足3NF。同时,原函数依赖集合中的每一个依赖都能在新的关系模式中找到,所以保持了函数依赖;通过外键客户号、商品号可以把三张表重新连接起来,所以是无损连接。这就是标准答案的完整思路。
做范式分解题,我总结了一个四步法:找码 → 判断是否存在部分/传递依赖 → 针对依赖拆分 → 验证无损连接和依赖保持。每一步都有章法可循,不用靠灵感。考前我建议你把老师PPT上所有范式例题自己独立做一遍,不是看一遍,是拿纸笔从找码开始一步步写。这个模块的熟练度直接决定你设计大题能拿多少分。
4. 实务重点:事务、并发控制与数据库恢复
如果说前面讲的范式负责“让表设计得更合理”,那么事务这块负责的是“让数据操作更可靠”。这几个章节理论性强、概念多,而且概念之间还有很强的逻辑关系。考试里一般会以简答题和分析题出现,很多同学能写出“ACID”这四个字母,但展开解释时就漏三落四。
4.1 事务的ACID性质
事务(Transaction)是数据库操作的一个执行单元,它里面的操作要么全部成功,要么全部失败回滚。ACID是四个性质的缩写,每个都必须能用术语+例子说明白:
原子性(Atomicity):事务中的所有操作是一个不可分割的原子单位。要么全做,要么全不做。转账就是最典型的例子:从A账户扣1000元,往B账户加1000元,这两个操作必须同时成功或同时失败。
一致性(Consistency):事务执行前后,数据库从一个一致性状态转换到另一个一致性状态。比如转账前后,两个账户余额的总数不变。
隔离性(Isolation):多个事务并发执行时,彼此之间互不干扰,一个事务的中间状态对其它事务不可见。
持久性(Durability):事务一旦提交,它对数据库的改变就是永久性的,即使系统崩溃也能恢复。
四个性质不是孤立的,实现机制也不一样。原子性和持久性靠日志(undo和redo日志)保证,隔离性靠并发控制协议保证,一致性靠完整性约束和应用逻辑保证。这个对应关系是简答题的高频问法:“数据库系统是如何实现事务的ACID性质的?”你要能写出这条逻辑链,而不是单纯背单词。
4.2 并发带来的三个问题
为何需要并发控制?因为多个事务同时操作同一份数据,会产生三类经典问题,每一类都必须能举出例子:
丢失更新。两个事务同时读到一个值,各自修改后写回,后写的覆盖了先写的。比如A和B同时读到余额为100,A加了50变成150,B减了30变成70后写回,最后余额是70,A的修改丢失了。
不可重复读。一个事务内两次读同一行数据,却读到不同的结果。原因是另一个事务在这期间修改了这行。A第一次读到余额100,这时B把余额改成了200,A再读一次就变成200了,这在同一个事务里读到了不同值。
幻读。一个事务按条件查询某些行,事务执行期间另一个事务插入了新的行,导致这个事务再次查询时“多出来”一些原本不存在的行,像幻觉一样。
这三个问题容易混淆,我建议用一个场景去记差异:丢失更新是“修改覆盖”,不可重复读是“同一条记录前后不一致”,幻读是“记录数量或范围变了”。理解到这个粒度,选择题基本十拿九稳。
4.3 封锁协议与隔离级别
解决并发问题的主要手段是封锁(Locking),分成两种基本锁:排他锁(X锁,写锁)和共享锁(S锁,读锁)。两者的兼容规则是:X锁和任何锁都不兼容,S锁和S锁兼容。意思是读的时候允许别人也读,但写的时候谁都不能碰。
三级封锁协议逐级加严:
| 封锁协议 | 加锁规则 | 解决的问题 |
|---|---|---|
| 一级封锁协议 | 修改数据前必须加X锁,事务结束才释放 | 防止丢失更新 |
| 二级封锁协议 | 在一级基础上,读数据前必须加S锁,读完后立即释放 | 防止丢失更新+不可重复读 |
| 三级封锁协议 | 在二级基础上,读数据前加S锁,事务结束才释放 | 防止丢失更新+不可重复读+幻读 |
隔离级别是SQL标准对并发控制的抽象,与封锁协议有对应关系:读未提交对应一级,读已提交对应二级,可重复读对应三级,串行化最强,通过强制事务串行执行来解决全部问题。考试常考的是让你针对某个隔离级别判断会出现哪种并发问题。
4.4 数据库恢复的基本策略
数据库恢复这块,核心思想是利用冗余来对付故障。系统崩溃后,内存中的缓冲数据可能丢失,磁盘上的数据可能只写了一半。恢复机制靠的是日志,日志记录了事务对数据库做的每一次修改。
恢复策略分两种:事务故障恢复通常用undo回滚未提交事务的修改;系统故障恢复要结合redo和undo,对已提交但没来得及写回磁盘的事务做redo,对未提交的事务做undo。介质故障则要从备份中恢复,再重做日志。
考试中比较经典的简答题是:“系统发生故障后,恢复子系统如何利用日志恢复数据库?”你组织答案时,抓住“检查点”这个关键点:以检查点为界,检查点之前的已提交事务可以不用重做,检查点之后的事务要按日志逐条分析,已提交的redo,未提交的undo。
这个概念我一开始学的时候也晕,后来把它类比成写论文时的“自动保存”:你写文档时,系统每隔一段时间拍一次快照,这就是检查点;你关机前手动保存过,这就是“已提交”;如果某个段落写了一半断电了,重新打开后,已经保存的内容保留下来,没保存的段落从草稿里回滚掉。数据库恢复的逻辑跟这个一模一样。
5. 期末冲刺:模拟卷与错题复盘实战
走到这一步,知识点已经成体系了,接下来就是把体系转化成做题能力。很多同学复习时有个误区:觉得自己把笔记看完了就万事大吉,结果一上考场发现题目问法和自己想的完全不一样。所以模拟卷这个环节不能省。我以一个包含三种典型题型的模拟卷为例,带你跑一遍完整的做题和复盘过程。
5.1 模拟卷实战一:SQL综合题
题目背景:一个学校数据库包含如下三张表:
- 教师(教师号,姓名,职称,工资)
- 课程(课程号,课程名,学分)
- 授课(教师号,课程号,学期)
问题:
- 查询职称为“教授”的教师姓名。
- 查询每门课程的开设学期数,输出课程号和学期数。
- 查询讲授“数据库”相关课程的教师姓名。
我的解答思路:
第一题最简单,单表查询:
SELECT 姓名 FROM 教师 WHERE 职称 = '教授';第二题要GROUP BY课程号,统计每个课程的学期种类数量:
SELECT 课程号, COUNT(DISTINCT 学期) AS 学期数 FROM 授课 GROUP BY 课程号;这里有一个细节:如果同一门课在同一个学期由多个教师授课,那么会有多条记录,你不用DISTINCT就会把同一个学期数两遍,所以DISTINCT是必须的。这个细节就是出题人埋的坑。
第三题要连接教师表和授课表,再从课程表里找课程名带“数据库”的课程:
SELECT DISTINCT 教师.姓名 FROM 教师 JOIN 授课 ON 教师.教师号 = 授课.教师号 JOIN 课程 ON 授课.课程号 = 课程.课程号 WHERE 课程.课程名 LIKE '%数据库%';这里SELECT后面加DISTINCT是因为一个教师可能教多门数据库相关课程,不排除会输出重复行。考试中,判卷老师很看重这类细节。
5.2 模拟卷实战二:范式分析题
题目:关系模式 学生选课(学号,姓名,课程号,课程名,成绩),已知函数依赖:学号 → 姓名,课程号 → 课程名,(学号,课程号)→ 成绩。求模式最高满足第几范式,并分解到3NF。
我的解答思路:
先找码。能够唯一确定一行的是(学号,课程号),因为学号决定姓名,课程号决定课程名,两者合起来决定成绩,所以码是(学号,课程号)。
判断范式:存在非主属性“姓名”对码的部分函数依赖(只依赖于学号),也存在“课程名”对码的部分函数依赖(只依赖于课程号),因此最高只满足1NF。
分解到3NF:把各自依赖的属性拆出来:
- 学生(学号,姓名)
- 课程(课程号,课程名)
- 选课(学号,课程号,成绩)
这三张表都不存在非主属性对码的部分或传递依赖,满足3NF,且保持了原有的函数依赖,并通过公共属性(学号,课程号)能重新连接起来,是无损分解。
这道题完全就是期末设计大题的出题套路。你发现没有,分解的结果在逻辑上就是把原来的大表拆成了三个职责单一的小表,这正是数据库设计的核心思想。
5.3 错题复盘的正确姿势
做完模拟卷,最忌讳的是对个答案就过去了。我建议你留出比做题更长的时间去做复盘。复盘分三步:
第一步,错题定位。找出每道错题对应的知识点,写在题目旁边。比如SQL错在这里,是因为HERE和HAVING的用法搞混;范式错在这里,是因为码找错了。不要只写“不会”,要写清楚“哪个环节不会”。
第二步,回归基础。针对定位到的知识点,回到PPT和教材里找到对应部分,把相关内容重新看一遍,再做一道类似题验证自己是否真懂了。这一步不能跳,否则错题会换个外壳再次出现。
第三步,归纳错因。按错因分类:概念不清、语法不熟、审题偏差、粗心大意。不同类型对应不同的应对方式。概念不清要重学,语法不熟要多练,审题偏差要慢读题,粗心大意就只能靠平时养成检查习惯。
有一套可行的复盘记录表如下,你可以自己用Excel或纸质表格画一个,每次做完题都填一次:
| 题目编号 | 涉及知识点 | 错误原因 | 改正方案 | 类似题目再做结果 |
|---|---|---|---|---|
| SQL第2题 | 分组聚合 | 没加DISTINCT | 重学GROUP BY语义,写一遍分组时考虑重复计数的场景 | 通过 |
| 范式第1题 | 候选码 | 把(学号,课程号)误判成唯一码 | 重做找码五道题,确认每个依赖链 | 通过 |
做完两三套模拟卷加上这轮复盘,你对知识点的掌握程度会有一个质的提升。比起盲目刷十套卷子,这种精做卷子加深度复盘的方式,才是考前性价比最高的冲刺打法。
6. 高频问题与考场避坑速查
最后这部分,我把平时答疑和考前辅导中遇到的高频问题汇总成一张问题速查表,并且分享几个考场上的实用技巧。这些问题如果你现在回答不上来,说明对应的知识点还有盲区,赶紧回头补。
6.1 高频问题速查表
| 问题 | 易错回答 | 正确要点 |
|---|---|---|
| 什么是外码? | 外码就是别的表的码 | 外码是本表的一个属性组,它不是本表的主码,但它是另一个表的主码,用于建立两表联系 |
| WHERE和HAVING的区别? | WHERE是行过滤,HAVING是组过滤 | WHERE在分组前执行,不能使用聚合函数;HAVING在分组后执行,必须搭配GROUP BY |
| 什么是自然连接? | 把两张表拼在一起 | 自然连接要求公共属性值相等,且去掉重复的公共属性列,是等值连接的特例 |
| 事务的原子性靠什么实现? | 靠锁实现 | 靠日志的undo机制实现,不是靠锁 |
| 什么样的视图不能更新? | 所有视图都不能更新 | 简单视图可以更新,含聚合函数、分组、DISTINCT、多表连接的视图通常不能更新 |
| 为什么BCNF比3NF更严格? | BCNF要消除所有依赖 | 3NF只消除非主属性的部分/传递依赖,BCNF还要消除主属性对码的部分/传递依赖 |
| 什么是幻读? | 读到了不存在的数据 | 是另一个事务插入了新行,导致同一查询在同一事务中两次执行得到不同结果集 |
| 数据库恢复时先做redo还是undo? | 先redo后undo | 恢复时根据需要反向扫描日志,先回滚未提交事务(undo),再重做已提交事务(redo),两者顺序取决于检查点策略,但记住“已提交的往前补,未提交的往后退” |
6.2 考场答题的三个关键细节
细节一:SQL题写完后检查表名和列名。考场上一紧张,很容易把题目给的列名写错,比如把“成绩”写成“分数”,把“教师号”写成“教师编号”。这种错误一分都得不值。我习惯读题时先把所有表名和列名圈出来,写完SQL再对照着检查一遍。
细节二:范式题一定要写判断过程。很多同学只写结论“满足3NF”,不给过程,这在考试里会扣掉大量过程分。正确的答法是先写“码是XX”,再写“非主属性为XX,存在/不存在对码的部分/传递函数依赖”,最后下结论。判卷老师是按步骤给分的,你写得越完整,即使最终判断错,也能拿不少步骤分。
细节三:简答题要分点作答,别写大段散文。阅卷是看采分点的。比如问“并发控制的主要技术有哪些?”,你就分点列出封锁、时间戳、多版本等,每点补充一句关键解释。分点作答的目的不仅是让卷面好看,更是强迫你自己理清思路,别把所有概念揉在一起。
6.3 临考一周的复习节奏建议
考前三天到一周这个阶段,不要再学习新知识了,重点做三件事:
一是重做错题和例题。把作业、模拟卷里做错的题和课程PPT上的经典例题重新做一遍,做对之后标个“过”,做错的标个“再战”,直到全部过关。
二是背诵核心概念。把简答题的考点整理成一页纸,比如ACID定义、三级封锁协议、日志类型、范式定义、视图优缺点、数据库安全措施等,每天早晚各背一遍。背的时候不要逐字背,抓住关键词,按逻辑串起来,考场上用关键词自然地组织成句。
三是保持手感。每天花一个小时,做10到15道选择填空,或者写3到5道SQL题,目的是让自己始终处于“做题状态”。考试最怕的就是手生,三天不写SQL,考场上写起来就犹豫,一犹豫就容易出错。
考试那天,记得提前十分钟到考场,把手机调静音,把一页纸的知识点最后翻一遍。进考场前深呼吸,告诉自己:该复习的已经复习到位了,剩下的就是把自己会的内容写到卷面上。
数据库期末复习,说白了就是一个把“散装知识”打包成“系统框架”的过程。我自己的复习体会是:一开始看什么都重要,什么都想背,越背越慌;后来按关系、SQL、范式、事务四条主线捋了一遍,再把做题踩过的坑记下来,上考场时心里反而很稳。这份笔记只是一个引子,真正值钱的是你花时间亲手做熟的那些例题和错题。把那几类核心题型的套路吃透,期末拿高分不是什么难事。