Ch1 数据库系统概论
原目录:数据库系统概论
Ch2 关系模型
原目录:数据库系统概论
1. 基本结构
- 属性(attribute):数据表列
- 元组(tuple):数据表行
- 域(domin):属性允许的取值集合
2. 数据库模式⭐
对比一般语言和SQL:
代数角度理解: 属性: 关系模式: 域: 关系r为域笛卡尔积子集: 关系实例由当前实际数据表决定 | 大学数据库的department表为例 | |
属性 | dept_name, building, budget | |
关系模式 | department(dept_name, building, budget) | |
关系实例 | ||
3. 数据表理论性质

4. 关系查询语言
(Relational Query Languages)
元组选择 | 列选择 | ||
笛卡尔积 | 并运算 | ||
差运算 | 交运算 | ||
自然连接 | 除运算⭐ | 参考链接: 关系代数中的除法运算 R÷S,即R中X的每个x对应像集Y包含S中Y属性的所有值 |
Ch3/4/6 SQL & 关系代数
原目录:数据库系统概论
SQL
1. 基本查询结构

⭐尽管典型的查询语句为SFW顺序,但真正的理解顺序为:
- from:对m个关系求笛卡尔积,产生候选元组集合
- where:依据谓词P对候选元组选择,只有使P为true时,将元组t加入结果关系(当省略P时,P默认为true)
- select:对结果关系进行指定属性的投影
2. 附加的基本运算
更多见: mid-term _Review
字符串操作 | |
结果排序 |
3. 聚集函数⭐
基本 | SQL提供五个基本聚集函数:
聚集函数不能直接出现在where语句中(可以在嵌套查询中使用): | |
group by | group by语句通常使用在聚集函数后,对查询结果进行分组
| |
having | having通常在group by后使用,非单独子句,用于筛选分组结果 |
4. 嵌套子查询
(Nested Subqueries)
4.1 嵌套查询
in/ not in | 先进行内查询,将结果视为集合常量与外表连接,再进行外查询
|
exists/ not exists | 对外表元组集合做for循环,依次带入内表查询,查询结果非空时返回true |
相关子查询 | 当外层的查询名称可以用在where子句的查询中,称为相关子查询 |
4.2 集合比较
some | 至少有一个满足就成立
|
all
| 所有都要满足
|
最值问题 |
|
with子句 | with提供了定义临时关系的方法,当嵌套查询过于复杂时,可提前使用with在查询开始定义关系 |
4.3 集合包含问题⭐
(空关系测试)
使用not exitst语句测试子查询结果集中是否不存在元组:
\(\\ \begin{align} &\quad关系A包含关系B\\ &\Rightarrow B\subseteq A\\ &\Rightarrow B-A= \varnothing\\ &\Rightarrow not \ exists(B\ except\ A) \end{align}\)

5. 数据库修改
5.1 删除
- 标准语句:
delete from where- 关于delete执行顺序:
delete from instructor
where salary < (select avg(salary) from instructor);执行中,avg(salary)在delete元组前就已经计算得到,不会因为删除和查询同时对于instructor而冲突
5.2 插入
- 标准语句:
// 形式一:自行输入插入数据
insert into table T values (r1, r2, r3);
// 形式二:从已有数据中选取插入数据
insert into table T
select r1, r2, r3 from B;
5.3 更新
- 标准语句
update T set r1 = r1';
6. 连接表达式
6.1 连接
连接类型 | 连接条件 |
|
|
例题 | |
给定关系 | 自然(内)连接:course natural join prereq中左侧CS-315发生失配,要想不丢掉数据,需要使用:
|
- 左/右/全外连接与内连接图示
参考链接: 【概念区分】笛卡尔积,自然连接,内连接,外连接(左,右,全)

6.2 连续连接
在SQL中,from语句允许一般化为以下格式
select A1, A2 … An
from E1, E2, … ,En
where P;其中Ei可以是单独关系模式R,也可以是自然连接语句,R1 natural join R2, 因此SQL中from中可以有三种搭配:
- 纯笛卡尔积: from R1, R2, R3
- 纯自然连接: from R1 natural join R2 natural join R3
- 混合: from R1 natural join R2, R3(不推荐)
但是对于给定关系模式,不同的连接结果可能不同,给定
- course(course_id, title, dept_name, credits)
- instructor(ID, name, dept_name ,salary)
- teaches(ID, course_id, sec_id, semester, year)
有以下两种选择:
// 1
select name, title
from instructor natural join teaches, course
where teaches.course_id = course.course_id;
// 2
select name, title
from instructor natural join teaches
natural join course;
结果不同,intructor与teaches自然连接后--(ID, name, dept_name, salary, course_id, sec_id, semester, year)
- 如果与course自然连接,需要满足属性集(course_id, dept_name)的完全匹配(不能只有一个属性相等)
- 如果使用where限定的笛卡尔积只用满足course_id上的相等即可被选出
因此,推荐使用using或者on语句,避免了自然连接与笛卡尔积混用,又保证了选择的有效性:
select name, title
from instructor natural join teaches join course using(course_id);关系代数
1. 基本运算
参考链接: Ch2 关系查询语言
选择运算 | 对应语句where,用于选择元组,谓词可使用and(∩),or(∪),not(∽)合并 符号:小写sigma:σ |
投影运算 | 对应语句select,用于列选择 符号:大写pi: Π |
集合并 | 对应操作select r from T and select s from T 符号:Π1+Π2 为了使r∪s有意义:
|
集合差 | 对应操作select r from T except select s from T 符号:Π1-Π2 r-s意义:包含在r但不包含在s中的关系,有意义的条件和集合并相同 |
⭐笛卡尔积 | 对应语句select r from T, S 符号:Π(σ(T×S)) |
更名 | 对应语句E as x,将x赋给表达式E做别名 |
2. 附加运算
集合交 | 对应查询:找出既在2009秋开设也在2010年春开设的课程 |
自然连接 | 对应语句:natural join 符号:σ(r⋈s) 当r与s没有任何相同属性时,r⋈s=r×s |
theta连接⭐ 对应语句:join on 自然连接的扩展,可以将选择运算和笛卡尔积合并,考虑关系r(R)和s(S),设θ是R∪S属性上谓词,则 | |
聚集函数 & 分组 |
|
Π投影选择需要的属性(列),当不进行Π投影,表示属性全选,即整个元组,不要过分纠结于Π投影和G的内外,具体情况具体分析,比如某地当需要count(course_id)>5时的student_id,此时Π就需要在G外侧再次选择一次student_id,否则结果元组会带着count属性 | |
除法运算 | 对应查询:集合包含问题 参考链接: 关系代数中的除法运算 R÷S,即R中X的每个x对应的像集Y包含S中Y属性的所有值 |
mid-term _Review
原目录:数据库系统概论 / Ch3/4/6 SQL & 关系代数
复习题
week4(大学数据库)
第七题: Find the sections that had the maximum enrollment in Fall 2009.
--写法一
select sec_id
from takes
where semester = 'Fall' and year = 2009
group by sec_id
having count(ID) >= all (select count(ID)
from takes
where semester = 'Fall' and year = 2009
group by sec_id);
--写法二
select sec_id
from takes
where semester = 'Fall' and year = 2009
group by sec_id
having count(ID) = (select max(count)
from takes
where semester = 'Fall' and year = 2009
group by count(distinct sec_id));集合比较
- some:至少有一个满足
- =some 等价于in
- <>some 不等价于not in
- all:所有都要满足
- =all 不等价于in
- 当子句是标量子查询(scalar subquery),相当于一般等号
- 当子句返回集合,=all()的结果集为NULL
- <>all 等价于not in
处理与最值有关的问题
- 使用>=all()或<=all()进行内外查询的比较
- 内查询使用max()/min()找出最值,外查询使用=比对
week5
第六题:Find the name and the SSN of everyone who works on all projects that his deparment is responsible for them.
select name, SSN
from employee as T
where not exists
(select pno
from project natural join department
where T.dno == department.dno)
except
(select pno
from (employee natural join hourlog) as S
where T.ssn = S.ssn);集合包含问题:A:某人从事的项目,B:其部门负责的项目,要求B包含于A->B-A=Ø
关系代数
\(\Pi_{name, ssn}((\Pi_{ssn,pno}(employee \bowtie hourlog)\div\Pi_{pno}(project \bowtie department))\bowtie employee) \)
含义:参考链接:https://www.cnblogs.com/yuanqi/p/4589967.html, R÷S表示R中每个X对应像集Y包含S中像集Y的所有值,本题RS÷S表示每个X,Y对应像集Z(x,y)中包含S中像集Y的所有值,
week6(大学数据库)
1(b):Delete all courses that have never been offered (that is, do not occur in the section relation).
delete from course
where course_id not in
(select course_id
from course natural join section);关于集合成员资格:
参考链接:https://blog.csdn.net/baidu_37107022/article/details/77278381
in/not in:先进行内查询,将结果集合与外表连接从而判断资格
- 适合外表大,内表小的情况
- 不适合内表记录有NULL情况,当内表结果有NULL时,内查询不返回记录
exists/not exists:对外表元组循环,带入内表查询
1(f):Enroll every student in the Comp. Sci. department in the section in Fall 2009, with sec_id of 1.
insert into takes
(select id, 'CS-001' as course_id, '1' as sec_id, 'Fall' as semester, '2009' as year
from student
where dept_name = 'Comp.Sci.');两种insert
insert into table values(...):适合手动填充数据
insert into table select (...):适合填充查询后数据
1(i):Delete all takes tuples corresponding to any section of any course with the word "database" as a part of the title; ignore case when matching the word with the title.
delete from takes
where course_id in (select course_id
from course
where title like "%database%" or title like "Database");模糊查找:like
- postgreSQL使用
ilike进行不区分大小写的模糊查找
- 字符串处理:
"intro%":以intro开头
"%body%":字符串中含有body
"---":字符串长度为3
"---%":字符串长度至少为3
week7
1(1):查询书名中有“%”的书目信息
select *
from title
where name like "%\%%";sql使用"\"作为转义符号
1(11):查询借阅图书本数超过2本的读者的读者号及借阅本数。
select memno, count(distinct book_id)
from member join book on borrowermemno = memno
group by memno
having count(distinct book_id) > 2;关系代数
\(_{memno,}\mathcal{G}_{count\_disinct(book_id)>2}(\sigma_{borrowermemno = memno}(member \times book )) \)
或者theta连接
\(_{memno,}\mathcal{G}_{count\_disinct(book_id)>2}(member \bowtie_{borrowermemno = memno} book ) \)
2(1):按借阅图书本数,从高到低列出读者的姓名及其借阅本数。
select fname, count(callnumber)
from member join book on borrowermemno = memno
group by memno
order by count(callnumber) desc结果排序:
- 降序:
order by ... desc
- 升序:
order by ... asc
2(2):查询借阅了123号读者和124号读者所借所有书目的读者的编号及姓名。
select memno, fname
from member as M
where not exists
(select memno
from member join book on borrowermemno = memno
where memno = 123 or memno = 124)
except
(select memno
from (member join book on borrowermemno = memno) as T
where M.memno = T.memno);集合包含问题:A:123和124所有所有图书,B:某人所借所有图书,要求A包含于B,A-B=Øor的使用:前后需要为完整的boolean值,不能使用where memno = 123 or 124或where memno = (123 or 124)
2(4):124号读者续借124号图书,请将预约归还日期延后一个月。
update book
set borrowerduedate = borrowduedate + interval '1 Month'
where book_id = 124;postgreSQL时间间隔:使用interval关键字,可使用hour,month,minute等作为单位,参考链接:https://blog.csdn.net/zacry/article/details/42742509
2(5):读者归还了124号图书,请修改其状态。
update book
set borrowermemno = null, borrowduedate = null
where book_id = 124;Ch7 E-R模型
原目录:数据库系统概论
1. E-R模型

- 弱实体集
有时联系集是冗余的,但删除后又无法凸显联系,只好在某个实体集中删除属性,但剩余属性不足以标识唯一指定的实体,必须依赖于一个强实体集,将其主键作为外键,并与弱实体集合的分辨符组成一组属性作为弱实体集主键 |
大学数据库为例
实体 | 学生Shankar | 弱实体集 |
实体集 | 所有学生 | section 依赖的强实体集为course 分辨符sec_id, semester,year |
联系 | 教师Katz和学生Shankar的联系advisor(导师) | |
联系集 | instructor和student中的advisor关联 |
2. 约束

3. E-R图

- 非二元联系
当联系集有不止一个箭头时

大学数据库为例
一对多关系 | ||
联系集上的基数约束 |
| |
弱实体集 | ||
复杂属性 |
| |
角色(联系) | course a是b的前置课,b是c的前置课,此时b具有两个角色 | |
非二元联系 | ||
大学数据库完整ER图

4. E-R图->关系模式

简单属性强实体集 | student(ID, name, tot_cred) | |
复杂属性强实体集 | instructor(ID, first_name, middle_initial, last_name , street_number, street_name, apt_number, city, state, zip, date_of_birth) ❗ 只表示复合属性的子属性 ❗ 不显式表示派生属性(函数) ❗ 为多值属性单独创建模式 | |
多值属性 | instructor_phone(ID, phone_number) | |
弱实体集 | section(ID, sec_id, semester, year[虚线]) | |
联系集 | 角色: prereq(course_id, prereq_id)(多对多) ❗ 关系模式中对外码没有明确的标注, 但默认联系集中来自某一个实体主码的属性就是参照该实体的外码 弱实体集周围: teaches(ID, course_id, sec_id, semester, year)(多对多) | |
5. 关系模式的冗余

合并举例
|
6. 设计问题

设计举例
比较takes联系集和注册信息registration实体集 |
❌虽然registration集合也准确记录了信息,但略显冗余. |
7. 其他特性
特化概化 | 聚集 |
8. E-R图标识总结
- 实体集&联系集

- 集合属性

- 映射基数&概化特化

- 其余可选表示


E-R建模例题
原目录:数据库系统概论 / Ch7 E-R模型
例1

E-R图 |
一种材料只能由一家提供,一家可提供多种材料,因此:
|
关系模式: 实体集 联系集 弱实体集 外码参照 |
Project (ID, name, money, class, start_time, end_time) Employee (ID, name, gender, title, birthday) Takes (Employee_ID, Project_ID)[Employee_ID, Project_ID分别参照Employee, Project] Manager (ID, name, gender, title, birthday) Manages (Manager_ID, Project_ID) [Manager_ID, Project_ID分别参照Manager, Project] Material (ID, name, kind, price) uses (Project_ID, Material_ID) [Project_ID, Material_ID分别参照Employee, Project] Supplier (Material_ID, name, phone, city) 根据 弱实体集 : supplier没有足够的属性表示唯一的供应商实体,即使每个supplier都唯一,不同material实体也会有相同的供应商实体,此时将supplies视为特使的联系集,只提供唯一标识Supplier实体的Material_ID,即弱实体集 |
例2

E-R图 |
关系模式: 实体集 联系集 弱实体集 外码参照 |
brand (id, name, country) model (id, name, price) option (id, name, price) car (VIN, price) dealer (id, name) customer (id, name) belong (brand_id, model_id) [外码brand_id, model_id参照brand, model] manufactured (VIN, model_id, option_id, time) [外码model_id, option_id参照model, option] sell (dealer_id, VIN, time) [外码dealer_id参照dealer] purchase (customer_id, VIN, time) [外码customer_id参照customer] |
Ch8 关系数据库设计
原目录:数据库系统概论
1. 好的关系设计
1.1 函数依赖
(functional dependency)
前提:关系模式的表示法
- 使用希腊字母表示属性集(α,β...)
- 使用大小写组合指示关系模式(r(R)),此时r表示关系r,R表示属性集合,当关系名称不重要时,只用R
- 如employee(id, name),简化(id, name)
- 当属性集是超码(一个或多个属性的集合,课区分唯一实体),用K表示,K是r(R)的超码
- 有时关系或关系的实例可仅用小写字母表示,如r
场景:分析关系模式
给定关系inst_dept

- 如果此时要求:每个系对应一个预算
- 需要:设计者在dept_name非当前模式主码情况下也能规定"一个dept_name对应一个budget"
- 等价于:如果有模式(dept_name, budget),则dept_name可以做主码,表示如下,即为函数依赖
\(dept\_name \rightarrow budget\\\)
- 通过该依赖可以发现inst_dept关系产生了大量重复记录,需要拆分为instructor, departmet
函数依赖 | 给定r(R)的实例,当实例满足函数依赖α->β的条件: |
作用 | 函数依赖帮助设计者发现模式是否冗余,需要拆分 |
个人理解 | 函数依赖是关系模式中属性或属性集间需要遵循的约束,由函数的角度可以视为不同属性间的映射f:α->β,函数具有单值的性质,函数依赖也类似,不允许出现在R中属性集α可以对应多个β |
1.2 关系模式的分解
employee(ID, name, street, city, salary) 按左图分解,右侧关系中可以知道某个(street, city, salary)下有个Kim,对于某大学中两个Kim,自然连接后产生4个结果,无法确定哪个是有意义的,称为有损分解
|
2. 原子域和第一范式
(atomic domain & first normal form)
参考链接: 范式理解与判断
概念引入:设计者根据函数依赖和其他数据依赖定义范式,再通过设计满足适当范式的模式来避免关系模式的冗余
函数依赖/数据依赖---->设计范式---->避免冗余
原子域 | 关系模式中,域指属性可取值的集合,而原子域的元素都是不可分的单元 |
第一范式 | 关系模式R的所有属性的域都是原子的 |
非原子域 | employee(id, name, children)中children是多值属性,即children取值可分,则关系具有非原子域,模式不属于第一范式 |
3. 使用函数依赖分解
3.1 码和函数依赖
函数依赖定义超码 | 如果函数依赖K->R在r(R)上成立,当K是r(R)超码: 对在r(R)的每个合法实例,实例中的每个元组对t1,t2,若t1[K]=t2[K]总有t1[R]=t2[R](t1=t2),则K是一个超码 |
函数依赖表示无法用超码表示的约束 | 对前文inst_dept(ID, name, salary, dept_name, building, budget)要求dept_name->budget成立,即 ID, dept_name->name, salary, building, budget |
3.2 函数依赖的使用
- 判定关系的实例是否满足给定函数依赖集F(被多个函数依赖约束)
- 说明合法关系集上的约束
举例
左侧关系r下: | 平凡(trivial)依赖:在所有关系都满足的依赖 | 依赖闭包(closure):集合闭包F+是根据F可推导出的所有函数依赖 如:给定r(A,B,C)若F:A->B,B->C在r上成立,则A->C一定成立,此时A->B,B->C,A->C共同构成F+ |
3.3 BC范式
(BCNF-Boyce-Codd Normal Form)
BCNF | 具有函数依赖集F的关系模式R属于BCNF的条件:对F+中所有形如α->β的函数依赖(α⊆R且β⊆R),下面至少一项成立
一个数据库设计属于BCNF的条件即设计的关系模式集中每个模式都属于BCNF |
举例 | inst_dept非BCNF,设计时要求"系-办公楼和预算"一一对应
inst_dept(ID, name, salary, dept_name, building, budget)的F+中有dept_name->budget, building,但dept_name本身非超码,因此模式中有冗余,需要拆分为instructor, department dept_name->budget, building |
非BCNF分解⭐ | 设R为非BCNF的一个模式,即存在至少一个非平凡α->β,使用以下两种模式取代R:
分解非BCNF后,产生的子模式可能依旧有一个或多个非BCNF,需要继续分解,最终结果为BCNF模式集合 |
4. 第三范式
4.1 BCNF的局限
给定以下联系集

要求 |
|
依赖 | 对应dept_advisor(s_id, i_id, dept_name)一定有以下函数依赖
|
问题 | 依赖一,i_id非超码(一个导师在某个系内可带多个学生) 依赖二,成立 |
分解 | (i_id, dept_name)和(s_id, i_id) 根据依赖一分解后均为BCNF(任何二属性关系模式都是BCNF),但无法保持依赖二 |
不足 | 有时的设计使得保持依赖(dependency preserving)很困难,需要一种比BCNF约束要弱的范式,设计的同时保持依赖--第三范式 |
4.2 3NF
具有依赖集F的关系模式R属于3NF的条件,对F+中所有形如α->β的函数依赖(α⊆R且β⊆R),下面至少一项成立
- α->β是平凡依赖
- α是R的一个超码
- β-α中每个属性A都包含于R的一个候选码(最小超码)中(β-α中每个属性A可以包含于不同候选码,无需同时在一个中满足)
根据定义,非3NF一定非BCNF
举例⭐
依赖一: i_id->dept_name | α=i_id, β=dept_name dept_name-i_id = dept_name | 在无法满足BCNF情况下: 为了保持依赖二成立,又(dept_name,s_id)是一个候选码,包含dept_name,因此该模式为3NF |
依赖二: dept_name, s_id->i_id |
5. 函数依赖理论
5.1 函数依赖集的闭包F+
逻辑蕴含 | 对r(R),给定依赖集F,当r(R)每一个满足F的实例也满足f,则f被r上依赖集F逻辑蕴含(logically imply) 离散数学中的蕴含关系p->q,只有p真q假时为假.依赖集F->f即当所有实例满足F,则一定满足f | |
依赖集闭包 | 根据逻辑蕴含定义,F+就是被F逻辑蕴含的所有函数依赖的集合 | |
armstrong公理系统 | 使用下列规则可寻找逻辑蕴涵的函数依赖:
| |
滚雪球算法 | 算法可结束:
| |
5.2 属性集闭包⭐
函数确定 | 若α->B(非β,只是单个属性B),则称属性B被α函数确定(functionally determine) | |
属性集闭包⭐ | 将给定依赖集F下被α函数确定的所有属性的集合称为F下α的闭包α+ | |
判断超码 | 若要判断α是否为超码
| |
属性闭包算法 | ||
例题⭐ | 对r(A,B,C,G,H,I),F如下 求(AG)+ | result=AG A->C中:A⊆result,result=ABCG 同理对CG->H,CG->I,B->H |
算法作用⭐ | 判断α是否为超码 | α+=R时,R中每个属性都可由α确定,α为超码 |
通过检查是否β⊆α+,检查α->β是否成立 | 当β⊆α+,说明α可以在给定F下确定β | |
计算F+: | 使用上面例题: | |
5.3 正则覆盖
(canonical cover)
检测 | F下的关系模式r(R),必须保证用户更新数据库后依旧满足F,这就需要检测,当检测不满足F时,回滚该操作 |
无关属性⭐ PDF221 | 去除函数依赖集中某个依赖的一个属性,不改变依赖集的闭包,则(此依赖中的)该属性无关(extraneous):
α->β,判断A在α中无关,要求依赖闭包在剔除A后不变,A的存在为了推出β: 只需说明F->{(F-f)∪((α-A)->β)},由公理,只需证F->{(α-A)->β},即β的推出和A本身无关: 为此,计算F+,当(α-A)->β)⊆F+,则A在α中无关
α->β,判断A在β中无关,要求依赖闭包在剔除A后不变,A的存在为了维持β,进而维持F: 为此,计算F下的闭包((α->(β-A))∪(F-f))+,当F⊆((α->(β-A))∪(F-f))+,则A在β中无关
|
正则覆盖⭐ | Fc是一个依赖集,使得F逻辑蕴涵Fc中所有依赖,并且Fc逻辑蕴含F中所有依赖.此外Fc必须有如下性质:
F<->Fc,对应离散数学中的"当且仅当(充要条件)",因此检验Fc和检验F的真值表应该一模一样,Fc即为"简化集" |
算法⭐ | 当遇到Fc=A->C,两侧都只有一个属性的属性集时,如果有一个无关属性,则这样空属性的函数依赖也要剔除 |
| 非唯一性⭐ | Fc初始化为F后,在Fc中选取不同的依赖f进行无关性检验并删去后,最终的到的正则覆盖结果不唯一 |
例题
对下列F求正则覆盖

Fc初始化为F
合并:
Fc: A->BC,B->C,AB->C
检验Fc的无关属性:
A在AB->C中无关 | 只需说明(B->C}能被Fc进一步推出:
B->C就在Fc中,则A无关 |
C在A->BC中无关 | 只需说明A->B可在Fc-f下进一步推出Fc: A->B和B->C可推出A->C,A->C和A->B可推出A->BC,则可推出Fc中所有依赖,C无关,Fc变为A->B,B->C |
所以正则覆盖为:A->B, B->C
5.4 二元无损分解
(lossless decomposition)
无损分解 | F是r(R)上的函数依赖集,令R1,R2为R的分解,若用r1(R2)和r2(R2)替代r(R)时没有信息损失,则称分解是无损分解. | |
关系代数角度⭐ |
| 将r投影到R1和R2上,对投影结果自然连接,若结果与r相同,则为无损连接,否则有损连接,如1.2 关系模式的分解中的例子,最后自然连接的结果为四个元组 |
函数依赖角度⭐ |
| |
充分条件 | 满足二元分解测试->证明是无损连接 但只有所有的约束都是函数依赖时才能说明: 满足无损连接->二元分解测试成立 | |
5.5 保持依赖
保持依赖 | 上文BCNF局限中的分解问题遇到了无法保持依赖的问题: |
限定:Fi | 令F为模式R上的依赖集,R1,R2...Rn为R的分解.F在Ri上的限定是F+中所有只包含Ri中属性的函数依赖集合Fi.由于一个限定中的所有函数依赖只涉及一个R中的属性,因此判定这种依赖是否满足可以只检查一个关系Ri. Ri是全体属性R中的部分属性,Fi是F中只与这些属性有关的函数依赖 |
限定的并集:F' | 根据限定的定义,F1,F2...Fn的集合就成为可以高效检查的依赖集.令F'=F1∪F2∪...∪Fn,F'是R上一个依赖集,通常F'≠F,但可能有F'+=F+ 当F'+=F+成立,F+⊆F'+,又F⊆F+,则F⊆F'+,根据属性闭包算法,F'->F,如果所有依赖满足F'即满足F |
5.6 保持依赖验证算法
算法 | 思想 |
输入:D(R1,R2...Rn)和R的依赖集F | 求F+➡求出所有限定Fi➡并取所有限定,得F'➡计算F'+➡比较F'+和F+ 👹弊端: 要计算F+,开销大 |
算法的根本目标:证明模式R中所有F下的α->β在分解R1,R2...Rn中依旧保持 | |
算法依据:5.5 限定的并集F',只要保证α->β在F'下保持 | |
算法实现:计算F'下α的闭包,当β⊆α+时,根据5.2 属性闭包算法作用,α->β成立,即α->β在F'中保持,当且仅当每一个α->β都保持,该分解是依赖保持的 | |
对F中每个α->β 此时属性闭包都是F下的:
| 算法的根本目标:同上 |
算法依据:见5.2 属性闭包算法作用中作用三,对每个γ⊆Ri:
F+在Ri上限定Fi中的依赖:指在Ri中依旧保持的F+中依赖,而(γ+∩Ri)是该依赖可确定的属性集 | |
算法实现:result初始为α while每次对一个Ri操作,验证F+中依赖在Fi中保持,当result不变,相当于验证每个依赖在F'下保持 |
5.7 候选码求法--LRN法
FD属性分类 | L类 | 仅在FD左边出现的属性 |
R类 | 仅在FD右边出现的属性 | |
N类 | 在FD两边均未出现的属性 | |
LR类 | 在FD两边均出现的属性 | |
定理 & 推论⭐ | 定理1 | 对给定R和F,当x∈R是L类属性,则x一定是候选码关键字成员 |
推论1 | 对给定R和F,当x∈R是L类属性,且x+包含了R的所有属性,则x是唯一候选码 | |
定理2 | 对给定R和F,当x∈R是R类属性,则x一定非候选码关键字成员 | |
定理3 | 对给定R和F,当x∈R是N类属性,则x一定是候选码关键字成员 | |
推论2 | 对给定R和F,当α∈R是N和L组成的属性集合,且α+包含R所有元素,则α是唯一候选码 | |
步骤⭐ |
| |
6. 分解算法
6.1 BCNF判定
一般判定 | 参照5.2 属性闭包算法,即判断α+是否等于R,可以证明: 只要F中的依赖都满足BCNF,F+中的也都满足 |
分解后判定⭐ | 当有R的F中有依赖不满足BCNF,从而分解,再次判定,但当前没有依赖包含Ri中所有属性,无法准确判断 例子:分解后 F中没有依赖能够判定R2是否满足BCNF,不能简单认为这种情况下就默认满足,伪传递律可得到AC->D,R2不满足,有时需要一个来自F+而不在F中的依赖才能额外判断这种情况 |
改进判定⭐ | 实战中非常重要的判定 |
6.2 BCNF分解算法
即第三部分3.3 BC范式:非BCNF的分解原理:R-β+α=>Ri-β
α->Ri不属于F+,这项要求保证了不会产生冗余的依赖,非常重要
结果
该算法产生无损的BCNF分解:
- 使用(Ri-β)和(α,β)取代模式Ri后,依赖α->β成立,且(Ri-β)∩(α,β)=α,参考无损分解的函数依赖角度,相当于(Ri-β)∩(α,β)->(α,β)属于F+,是无损分解
- 若没有要求α∩β=Ø,那α∩β中的属性不会出现在(Ri-β)中,那α->β不再成立
6.3 3NF分解算法
3NF算法中有两点注意:
|
例题
以4.1图中dept_advisor(s_id, i_id, dept_name)为例, 要求满足的两个依赖为:
- i_ID->dept_names_ID
- dept_name->i_ID
而且恰好为Fc,则R1=(i_ID, dept_name),R2=(s_ID, dept_name, i_ID),又因为(s_ID, dept_name)就是候选码,无需创建新模式,但R1产生冗余,删去,最终产生保持依赖且无损的3NF,R(s_ID, dept_name, i_ID)
- 3NF算法拓展⭐
3NF算法的结果可能属于BCNF,因此进行BCNF分解可以:
先使用3NF算法,对结果中不满足BCNF的进行分解,如果结果没有保持依赖,则只能恢复到3NF,否则就是BCNF
6.4 3NF对比BCNF
3NF | BCNF | |
优点 | 可以在无损且保持依赖的情况下得到设计 | 没有冗余 |
缺点 | 可能需要null占位保持某些联系,或者可能有冗余 | 无法保持某些函数依赖 |
sql设计 | 大多数数据库系统在检查非主码约束的函数依赖很困难,因此3NF的妥协导致了设计时的困难 | 对于无法保持的依赖,使用物化视图计算被拆散的依赖,投影为αβ,利用unique(α)或primary key(α)可以在物化视图上检查这些依赖 |
实际 | 在无法得到保持依赖的BCNF分解时,优先考虑使用物化视图的BCNF,而非3NF | |
7. 多值依赖和其余范式
教材 | 参考PDF228开始内容 |
知乎 | 关于函数依赖和范式的知乎回答: 如何解释关系数据库的第一第二第三范式? - 刘慰的回答 - 知乎 |
8. 数据库设计过程
得到r(R)的三种方式 |
|
ER模型与规范化 | 如果ER图设计的好,应该无需过多的规范化,以大学数据库为例: |
若在instructor中包含了属性dept_name和dept_address,且又有依赖dept_name->dept_address,就一定需要规范化 | |
注意,二元以上联系集可能使得模式不属于期望得范式 总结:规范化既可以在建模时靠分析实现,也可以对于现有模型进行规范化 |
规范化例题
原目录:数据库系统概论 / Ch8 关系数据库设计
例1
给定关系模式EMP_DEPT 1.“EmployeeNo”, “EmployeeName”, “BornDate” and “EmployeeAddress” represent the ID number, name, date of birth, and address of an employee. 2.“DepartmentNo”, “DepartmentName”, and “DepartmentAddress” represent the ID number, name, and address of a department. 3.“ProjectNo” and “ProjectName” represent the ID number and name of a project. 4.“WorkHours” represents the working hours of an employee in a project. |
一些设定: A department has more than one employee; Two employees maybe have the same name; An employee works in a unique department; An employee can take part in several projects; Two or more employees from different departments can take part in a same project; An employee can take part in more than one project; The working hours of an employee in different project may be different. |
- Identify functional dependencies.
有以下函数依赖: 易错点: |
- Determine all candidate keys of the relational schema.
![]()
- Is the realtional schema in BCNF? Why? If not, bring it to a set of BCNF schemas, and identify their candidate keys and foreign keys

例2
考虑关系模式R = {A, B, C, D, E}, 函数依赖集FD = { A→C, B → D, AB → CD, E → B} (1)求R的候选码。 (2)下列函数依赖哪些成立? a. E → D b. A → B c. AB → CE d. AE → CB (3)R是否满足BCNF?请说明理由。若不满足,请将R规范化为一组BCNF关系模式。 |
- 参考:5.7 候选码求法--LRN法
首先排除R类属性BCD
A+≠R且E+≠R
(AE)+=R,则候选码是AE - 参考:5.2 属性闭包算法作用

- 参考: 6.2 BCNF分解算法
易错点: |
Ch14/15 事务管理
原目录:数据库系统概论
Ch14 事务
PDF P385
1. 并发控制
两种调度方式
串行 | 并行 |
串行(serial):同一事务的指令集中在一起执行 | 并发:可以间断的切换处理事务 |
2. 可串行化(serializable)
定义:将并发执行的调度等价为一种串行的调度(一组事务的调度包含该事务所有指令,不能中间插入)
2.1 冲突可串行化
对于read和write指令,调度S种分别属于事务i,j的指令,有以下组合
i=read, j=read | i, j次序无关紧要 |
i=read, j=write | write的先后决定了read的数据是否产生变化 |
i=write, j=read | 同上 |
i=write, j=write | 对于S的下一条read有影响,它只能read后write的值 |
因此,不同事务上对相同数据项的操作,其中至少有一个write指令时,i,j是冲突的
2.2 冲突等价
i,j是调度S的两条连续指令,从属于不同事务且不冲突,则可以交换i,j得到新的调度S',S等价于S',因为i,j的顺序改变不会影响事务处理,常见的交换:
T1的read(A)<-->T2的read(B) |
T1的read(A)<-->T2的write(B) |
T1的write(A)<-->T2的read(B) |
T1的read(A)<-->T2的read(A) |
2.3 可串行化判断
使用"优先图",G(V,E),V作为点集,每个顶点就是一个事务Ti,边集由满足下列条件的边Ti->Tj组成:(恰好对应三种矛盾)
Tj执行read(Q)前,Ti执行write(Q) |
Tj执行write(Q)前,Ti执行read(Q)(Ti还未执行write(Q)) |
Tj执行write(Q)前,Ti执行write(Q) |
举例
调度 | 优先图 |
T1所有的命令都先于T2执行,因此优先图就是两点一线 | |
T2的write(A)前执行了T1的read(A),产生T1->T2,T1的write(B)执行前,T2执行了read(B)因此有T2->T1,最终形成环 ⭐结论:只有优先图中无环的调度才能冲突串行化 |
2.4 串行化顺序确定
使用拓扑排序生成串行化顺序(不唯一)
👇下图可能的串行化顺序:Ti->Tj->Tk->Tm或Ti->Tk->Tj->Tm

2.5 冲突等价与可串行化区别
- 可串行化是一组事务的调度包含该事务所有指令,不能中间插入,一般表示为<T1,T2,...,Tn>
- 冲突等价是针对不同事务指令的交换,一般使用图示
Ch15 并行控制
1. 基于锁的协议
1.1 两种锁
共享锁lock-s | Ti获得Q上的共享锁-->Ti只能读Q,不能写 |
排他锁lock-x | Ti获得Q上的排他锁-->Ti可以读,写Q |
1.2 相容函数
如果T2请求Q上的锁B,但事先已有T1获得了Q上的锁A,如果此时T2能够立即获得锁,则称A,B锁是相容的,否则只能等T1解锁后T2才能获得,在此之前T2只能等待
- lock-s与lock-x的相容矩阵Comp
1.3 两阶段锁协议
保证可串行性的一个协议是"两阶段封锁协议",分为两个阶段提出加速和解锁申请:
(两个阶段都是针对一个事务来说)
- 增长阶段(growing phase):事务可获得锁,不能释放锁
- 缩减阶段(shrinking phase):事务可释放锁,但不能获得锁
两阶段封锁可以保证可串行性,但无法保证避免死锁
- 封锁点:对于任何事务,在调度中该事务获得其最后加锁的位置(增长阶段结束点)
多个事务根据封锁点排序,得到的顺序就是可串行化顺序
1.4 三类二阶段锁协议
分类 | 特点 |
一般 |
|
严格(strict) |
|
严酷(rigorous) |
|
1.5 锁转换
定义 | 锁转换(lock conversion),提供一种lock-s和lock-x转化的方式,从而减少等待或饥饿,提高并发度 |
分类 |
|
两阶段操作 |
|
机制总结 |
|
举例
对左侧调度采用普通两阶段协议: 使用锁转换: | 忽略读写的调度: |



