写在前面:
Created by Inori_333 from SDU.
这是给我自己速通2023年冬季学期的数据库系统概念期末考试而做的Note,发出来希望可以帮助到大家。知识点是乱序的,因为这是按照学校历年期末题的题目,在复习的时候整理的。有一部分内容是我自己的理解,如果有错误,请您在评论区留言或者私信我,我会尽快订正。如果想快速找到想找的知识点,可以使用文章目录,或者借助浏览器的Crtl+F快速查找。
如果您觉得这篇文章帮到了您,请点个赞喵~
一、简答题知识点
1.1文件系统与数据库系统的区别和联系
文件系统 | 数据库系统 |
程序和数据有一定联系 | 程序和数据分离 |
用操作系统存取方法对数据进行管理 | 用DBMS对数据进行管理 |
实现以文件为单位的数据共享 | 实现以记录为单位的数据共享 |
用文件将数据长期保存在外存上 | 用数据库对数据进行统一存储 |
联系:都是数据组织的管理技术,均有数据管理软件管理数据,程序与数据之间都用存取的方式进行转换,数据库系统是基于文件系统的。
1.2事务调度
可串行化:并发的调度等价于某个串行调度的结果。
1.2.1冲突可串行化
如果一个调度S与一个串行调度S'冲突等价,则称调度S是冲突可串行化(conflict serializable)的。
判断可串行化的常用方法是使用优先图,也就是借助图结构对事务集合进行拓扑排序(topological sort)。
1.2.2可恢复调度
事务的可恢复性是为了保证事务的原子性。
一个可恢复调度(recoverable schedule)应该满足:对于每对事务Ti和Tj,如果Tj读取了之前由Ti所写的数据项,则Ti先于Tj提交。
1.2.3无级联调度
因单一事务故障而导致一系列事务回滚的现象成为级联回滚(cascading rollback)。
避免级联回滚的调度成为无级联调度(cascadeless schedule):对于每对事务Ti和Tj,如果Tj读取了之前由Ti所写的数据项,则Ti必须在Tj的这一读操作之前提交。
1.2.4事务隔离性级别
可串行化:通常保证可串行化调度。
可重复读:只允许读取已提交数据,而且在一个事务两次读取一个数据项期间,其他事务不得更新该数据。但该事务不要求与其他事务可串行化。
已提交读:只允许读取已提交的数据,但不要求可重复读。
未提交读:允许读取未提交的数据。这是SQL允许的最低一致性级别。
1.3并发控制
在实践中,最常用的并发控制方式是两阶段封锁协议和快照隔离。
1.3.1基于锁的协议
1.3.1.1锁的类型
共享锁:如果事务Ti获得了数据项Q上的共享型锁(记为S),则Ti可读但是不能写Q。
排他锁:如果事务Ti获得了数据项Q上的排他型锁(记为SX),则Ti可读也可写Q。
1.3.1.2基于锁的数据操纵过程
每个事务都要根据自己将要对数据项Q执行的操作类型申请适当的锁。事务只有在控制管理器授予所需要的锁之后才能继续操作。
要访问一个数据项,事务Ti必须先给数据项加锁。如果该数据项已经被加上了不相容类型的锁,则在所有其他事务持有的不相容类型的锁被释放之前,并发管理器不会授予锁。因此,事务Ti必须等待,直到所有不相容锁被释放。
死锁(deadlock):For example,事务Ti拥有B上的排他锁,而事务Tj正在申请B上的共享锁,因此需要等待Ti释放其排他锁。而事务Ti正在申请A上的排他锁,而事务Tj此时正拥有A上的共享锁,因此也需要等待Tj释放其共享锁。这就导致了事务无法正常执行下去。
解决死锁的方法是事务回滚。
事务往往要服从封锁协议。当且仅当一个封锁协议的所有合法调度均是冲突可串行化的,我们称这个封锁协议保证冲突可串行性。
饿死(starved):有可能存在一个事务序列,其中每个事务申请对该数据项加共享型锁,每个事务在授权加锁后的一小段时间内释放锁,而申请加排他锁的事务就一直没办法加上排他锁,这个事务也就一直没办法继续执行。
避免饿死的方式:约束并发控制管理器的加锁条件:
当事务Ti申请对数据项Q加M型锁时,
(1)不存在数据项Q上持有与M型锁冲突的锁的其他事务。
(2)不存在等待对数据项Q加锁且先于Ti申请加锁的其他事务。
1.3.1.3两阶段封锁协议
事务分两阶段提出加锁和解锁申请。
(1)增长阶段:事务可以获得锁,但不能释放锁;
(2)缩减阶段:事务可以释放锁,但不能获得新锁。
可以证明,两阶段封锁协议保证冲突可串行化。对于任何事务,在调度中获得其最后加锁的位置,成为事务的封锁点(lock point)。这样,多个事务可以根据其封锁点进行排序。
两阶段封锁协议不能保证不发生死锁。
1.3.1.4严格两阶段封锁协议
防止级联回滚。要求事务持有的所有排他锁必须在事务提交之后释放。
1.3.1.5强两阶段封锁协议
要求事务提交之前不能释放任何锁。
1.3.1.6多粒度封锁协议
将从数据库到记录的分级构造为树形(常见的)结构,当对上层节点显式加锁时,对其所有子节点隐式加锁。
为了判断能否给上层节点加锁(因为其他事务可能目前持有部分未释放的锁),引入新的锁类型:意向锁。希望给某个节点Q加锁的事务必须遍历从根到Q的路径,并给路径上的各节点加上意向锁。
共享型意向锁(IS锁):将在树的较低层进行显式封锁,但只能加共享锁。
排他型意向锁(IX锁):将在树的较低层进行显式封锁,但只能加排他锁或共享锁。
共享排他型意向锁(SIX锁):以该节点为根的子树显式地加上了共享锁,并且将在树的更低层显式地加上排他锁。
锁的相容矩阵:
IS | IX | S | SIX | X | |
IS | true | true | true | true | false |
IX | true | true | false | false | false |
S | true | false | true | false | false |
SIX | true | false | false | false | false |
X | false | false | false | false | false |
多粒度封锁协议要求加锁按照自顶向下的顺序,而释放按照自底向上的顺序。
1.3.2基于时间戳的协议
对于每个事务,把一个固定的时间戳和它联系起来。
1.3.3基于有效性检查的协议
对于每个事务,按照两阶段或三阶段执行:
(1)读阶段:在这一阶段,系统执行事务;所有write操作都是对局部临时变量进行的,并不对数据库进行更新。
(2)有效性检查阶段:对事务进行有效性测试。判定是否可以执行write而不违反可串行性。
(3)写阶段:如果通过了有效性检查,则将临时变量的值写入数据库。
1.4索引
1.4.1聚簇索引(聚集索引)与主索引
一个文件可以有多个索引,分别基于不同的搜索码。如果包含记录的文件按照某个搜索码指定的顺序进行排序,那么该搜索码对应的索引称为聚簇索引(clustering index)。聚簇索引也称为聚集索引,主索引(primary index)。聚簇索引通常建立在主码上,但并非必须如此。
除了聚簇索引之外的索引统称为非聚簇索引或者辅助索引。
1.4.2稠密索引与稀疏索引
索引项(index entry)或者索引记录(index record)由一个搜索码值和指向具有该搜索码值的一项或多项记录的指针构成。指向记录的指针包含磁盘块的标识和标识磁盘块内记录的块内偏移量。
稠密索引(dense index):文件的每个搜索码值都有一个索引项。
在稠密聚簇索引中,索引项包括搜索码值和指向具有该搜索码值的第一条数据记录的指针。具有相同码值的其余记录按照顺序存储在第一条记录之后,由于该索引是聚簇索引,因此记录根据相同的搜索码值排序。
在稠密非聚簇索引中,索引必须指向所有具有相同搜索码值的记录的指针列表。
稀疏索引(sparse index):只为搜索码的某些值建立索引项。只有当关系按照搜索码排列顺序存储时才能使用稀疏索引,换句话说,只有索引是聚簇索引时才能使用稀疏索引。
1.4.3辅助索引
辅助索引必须是稠密索引,对每个搜索码值都有一个索引项,而且对文件中的每条记录都有一个指针;而聚簇索引可以是稀疏索引,可以只存储部分搜索码的值。
1.4.4多级索引
顾名思义,一级索引不能满足需求时可以建立多级索引。
1.5码
1.5.1超码
超码(superkey)是一个或多个属性的集合。这些属性的组合可以使我们在一个关系中唯一地标识一个元组。超码的任意超集也是超码。
1.5.2候选码
超码中可能包含无关紧要的属性。如果一个超码的任意真子集都不能成为超码,这样的超码称为候选码(candidate key)。
1.5.3主码
主码(primary key)是被数据库设计者选中的,用来在一个关系中区分不同元组的候选码。
1.5.4外码
一个关系模式R1可能在其属性中包含另一个关系模式R2的主码。这个属性在R1上被称作参照R2的外码(foreign key),关系R1也称为外码依赖的参照关系(referencing relation)。
1.5.5搜索码
用于在文件中查找记录的属性或属性集称为搜索码(search key)。
一个包含多个属性的搜索码成为复合搜索码(composite search key)。
1.5.6部分码
弱实体集的分辨符(discriminator)也称为该实体集的部分码。
1.6事务恢复
1.6.1日志与事务提交
undo:使用一个日志记录,将该日志记录中指明的数据项设置为旧值。undo作为撤销过程的一部分,还会写下日志记录下来所执行的更新。这些日志是特殊的redo-only日志记录,因为其不需要包含所更新的数据项的旧值。事务Ti的undo操作执行结束后,会写一个<Ti abort>的日志记录,表明撤销完成。
redo:使用一个日志记录,将该日志记录中指明的数据项设置为新值。
如果日志包含<Ti start>记录,不包含<Ti commit>或者<Ti abort>记录,则需要执行undo操作。如果日志包含<Ti start>记录,以及<Ti commit>或<Ti abort>记录,则需要执行redo操作。
提交:当一个事务的提交日志记录输出到稳定存储器,我们说这个事务提交了。
1.6.2检查点
在检查点执行过程中,不允许任何事务的更新动作。在发生系统崩溃之后,只需要对最后一个写入到稳定存储器的检查点直到崩溃发生时最新的日志执行undo和redo就可以了。优化了数据库的恢复效率。
1.6.3什么时候日志缓冲区需要刷盘
常见的情况:
(1)事务提交时;
(2)日志缓冲区满时;
(3)设置系统检查点时;
(4)脏页写回磁盘时。
1.7E-R图
1.7.1E-R图要满足3个基本约束
映射基数约束、参与约束和码约束。
1.7.2E-R图的基本元素:
(1)分割为两部分的矩形:实体集;
(2)菱形:联系集;
(3)未分割的矩形:联系集的属性;
(4)线段:将实体集连接到联系集;边上的0..*表示的是最小映射基数为0,最大没有限制。
(5)虚线:将联系集属性连接到联系集;
(6)双线:显示实体集在联系集中的参与度;
(7)双菱形:代表弱实体集的标志性联系集。
(8)虚下划线:弱实体集的分辨符;
(9)实下划线:实体集的主码;
1.7.3 E-R图相关的基本概念
(1)实体集:相同类型具有相同属性的实体的集合。实体是现实世界中可区别于其他所有对象的一个“事物”。
(2)联系集:相同类型联系的集合。联系指的是多个实体之间的相互关系。
(3)属性:每个属性都有一个可取值的集合成为域。
(i)简单和复合属性:简单属性即原子属性,复合属性是可以拆分为简单属性的属性。
(ii)单值属性和多值属性:对于每一个特定实体都只有单独的一个值的属性成为单值属性;其余的成为多值属性。
(iii)派生属性:这类属性的值可以从别的相关属性或实体派生出来。
(4)弱实体集:没有足够的属性以形成主码的实体集;
(5)强实体集:有主码的实体集;
(6)弱实体集必须与另一个成为标识(identifying)或属主实体集(owner entity set)的实体集关联才有意义。也就是说,弱实体集存在依赖于标识实体集。将二者的联系成为标识性联系。标识性联系是从弱实体集到标识实体集多对一的,并且弱实体集在联系中的参与是全部的。
(7)全部参与的:实体集E中的每个实体都参与到联系集R的至少一个联系中。
(8)部分参与的:实体集E中只有部分实体参与到R的联系中。
(9)特化:在实体集内部进行分组的过程成为特化(specialization)。
(10)概化:从概念上来说,两个实体集之间包含相同的属性,这种共性可以通过概化(generalization)来表达,概化是高层实体集与一个或多个底层实体集之间的包含关系。高层与低层实体集也分别被称为超类和子类。
1.8语法树与语法树优化
1.8.1物化
一般就是说,把一个运算表达式画成一棵运算符树,来实现抽象计算顺序的图形化。其中具体来说,物化是指运算的每个中间结果都被创建并体现了。
1.8.2如何画语法树
简单来说,按照你学二叉树时候的直觉来画。单元运算(比如投影、选择),就往下画一条竖线,子树层不分叉;双元运算(比如自然连接),就分成两叉,来表示自然连接的两个对象。
1.8.3如何优化语法树
先把原表达式的语法树画出来,然后记住一个原则:优化语法,实际上就是提高执行效率,缩短执行时间,减少执行空间占用。这往往是通过减少运算过程中表的规模来实现的,也就是说,选择运算和投影运算往往越早越好,尤其是选择运算,这样可以减少元组的规模,从而提高运算效能。
二、证明题知识点
2.1原子域和第一范式
一个域是原子的,如果其不具有任何可分的子结构(比如多值属性和组合属性)。我们称一个关系模式属于第一范式(1NF),如果其所有属性的域都是原子的。多值属性:比如phone_number属性——一个人可以有0~∞个手机号码;组合属性:比如属性address——其内部还包含二级属性city,street,zip等等。
2.2使用函数依赖进行分解
一个关系模式r(R),有α⊆R,β⊆R。
- 给定r(R)的一个实例,我们说这个实例满足函数依赖α→β的条件是:对实例中所有的元组对(t1,t2),若t1[α]=t2[α],则t1[β]=t2[β]。
- 如果r(R)的每个合法实例都满足函数依赖α→β,则我们说该函数依赖在模式r(R)上成立。
这意味着,如果函数依赖K→R在r(R)上成立,则K是r(R)的一个超码。
平凡的(trival)函数依赖:在所有关系中都满足:例如A→A,AB→A。
我们使用来表示集合F的闭包(closure),也就是能够从给定的集合F推导出的所有函数依赖的集合。
2.2.1Boyce-Codd范式(BCNF)
BCNF消除所有基于函数依赖能发现的冗余。具有函数依赖集F的关系模式R属于BCNF的条件是:对中所有形如α→β的函数依赖(其中α⊆R,β⊆R),下面至少有一项成立:
- α→β是平凡的函数依赖(即β⊆α)。
- α是模式R的一个超码。
分解不属于BCNF的模式的一般规则:
用以下两个模式取代R:
- (α∪β)
- (R-(β-α))
当对不属于BCNF的模式进行分解时,得到的结果可能有一个或多个不属于BCNF,这种情况下我们需要进一步分解,其最终结果是一个BCNF模式的集合。
2.2.2BCNF和保持依赖
保持依赖没看懂。
2.2.3第三范式3NF
具有函数依赖集F的关系模式R属于3NF的条件是:对中所有形如α→β的函数依赖(其中α⊆R,β⊆R),下面至少有一项成立:
- α→β是平凡的函数依赖(即β⊆α)。
- α是模式R的一个超码。
- β-α中的每个属性A都包含于R的一个候选码中。
2.3函数依赖理论
2.3.1函数依赖集的闭包
2.3.1.1逻辑蕴涵
给定关系模式r(R),如果其中的每一个满足F的实例也满足f,则称R上的函数依赖f被r上的函数依赖集F逻辑蕴涵。F的闭包是被F逻辑蕴涵的所有函数依赖的集合。
2.3.1.2Armstrong公理与闭包计算
Armstrong公理:
(1)自反律。若α为一属性集且β⊆α,则α→β成立。
(2)增补律。若α→β成立且γ为一属性集,则γα→γβ成立。
(3)传递律。若α→β和β→γ成立,则α→γ成立。
另外的一些适用规则:
(1)合并律:若α→β和α→γ成立,则α→βγ成立。
(2)分解律:若α→βγ成立,则α→β和α→γ成立。
(3)伪传递律:若α→β和γβ→δ成立,则αγ→β成立。
2.3.2属性集的闭包
求法和函数依赖闭包的求法类似。算法的执行时间为F集合规模的二次方。
属性闭包的用途:
- 判断α是否为超码:计算,检查其是否包含R中的所有属性。
- 通过检查是否β⊆,可以检查函数依赖α→β是否成立。
- 提供了一种计算的方法:对任意的γ⊆R,找出闭包;对任意的S⊆,我们输出一个函数依赖γ→S。
2.3.3正则覆盖
无关属性:去除后不改变函数依赖集闭包的属性。
F的正则覆盖是一个函数依赖集,使得F逻辑蕴涵中的所有依赖,并且逻辑蕴涵F中的所有依赖。此外,满足以下性质:
- 中的任何函数依赖都不含无关属性。
- 中函数依赖的左半部都是唯一的。
正则覆盖有公式求法,不再赘述。
2.3.4无损分解和有损分解
无损分解:假设R分解为了R1和R2,则以下函数依赖至少有一个属于:
- R1∩R2→R1
- R1∩R2→R2
简单来说就是R1和R2两个集合需要同时包含R1或者R2的一个超码。否则就是有损分解。有损分解再重新合成后可能会导致元组信息的变化(比如多出来一些原本没有的元组)。
2.3.5保持依赖
如上所说,我没看懂。
2.4分解算法
2.4.1 BCNF分解
上面在写BCNF的时候顺手写了。
一个显而易见的结论:如果一个关系只有2个属性,其一定为BCNF。
2.4.2 3NF分解
首先求F的正则覆盖,之后对中的每个函数依赖α→β,建立一个模式Ri:αβ。
如果模式Rj,其中j=1,2,3,...,i都不包含R的候选码,那就新增一个关系模式R(i+1),指定其为R的任意一个候选码。
最后进行去重,删除被包含候选码的关系模式Rx所包含的所有关系,就得到了3NF分解的结果。
2.5多值依赖与第四范式(4NF)
2.5.1多值依赖
函数依赖又称相等产生依赖(equality-generating dependency),而多值依赖称为元组产生依赖(tuple-generating dependency)。
多值依赖:实际上就是检查α→β和α→(R-β)是否独立。
令D表示函数依赖和多值依赖的集合。D的闭包是由D逻辑蕴涵的所有函数依赖和多值依赖的集合。由多值依赖的定义可以导出以下规则:
- 若α→β,则α→→β。即每个函数依赖都是多值依赖。
- 若α→→β,则α→→R-α-β。
2.5.2第四范式(4NF)
每个4NF模式都属于BCNF,但有些BCNF模式不属于4NF。
具有函数依赖和多值依赖集D的关系模式r(R)属于4NF的条件是:对中所有形如α→→β的多值依赖(其中α⊆R,β⊆R),下面至少有一项成立:
- α→→β是平凡的多值依赖。
- α是模式R的一个超码。
2.5.3 4NF分解
和BCNF分解算法一样,只是把函数依赖拓展到多值依赖。
三、计算题知识点
3.1关系运算
3.1.1关系代数运算的执行开销
3.1.1.1选择运算
表示文件中块的数量。
算法 | 开销 | 原因 | |
A1 | 线性搜索 | 一次初始搜索+个块传输 | |
A1 | 线性搜索,码属性等值比较 | 平均: | 最多就一条记录满足条件 |
A2 | B+树主索引,码属性等值比较 | 索引查找穿越树高度+一次I/0取记录(一次搜索+一次块传输) | |
A3 | B+树主索引,非码属性等值比较 | 树的每层一次搜索,第一个块一次搜索。b是包含指定搜索码记录的块数。假定这些块是顺序存储(因为是主索引)的叶子块并且不需要额外搜索 | |
A4 | B+树辅助索引,码属性等值比较 | 类似主索引情况 | |
A4 | B+树辅助索引,非码属性等值比较 | n是所取记录数。代价与A3类似,但是因为每条记录可能在不同的块上,因此每条记录需要一次搜索。 | |
A5 | B+树主索引,比较 | 与A3非码属性等值比较一样 | |
A6 | B+树主索引,比较 | 与A4非码属性等值比较一样 |
3.1.1.2连接运算
主要考察运算逻辑。
3.1.1.2.1嵌套循环连接
3.1.1.2.2块嵌套循环连接
3.1.1.2.3索引嵌套循环连接
3.1.1.2.4归并连接
3.1.1.2.5散列连接
3.2SQL语句
知识点是乱序的。想快速找到可以看文章目录。
3.2.1 查询结果的排序
降序排序:order by (选择的排序基准属性)desc;
升序排序:order by (选择的排序基准属性);
3.2.2 不含有...(属性B的指定值)的属性A的值
where ... not in (...以下省略)
3.2.3 查找所有A都...的属性值
where not exists (...以下省略)
3.2.4 更新update
update 表名
set 属性名=对属性的操纵
where 筛选条件