- 基本概念
- 数据库的三级模式结构
- 数据模型
- E-R 模型
- 关系模型
- 各种键
- 完整性约束
- 关系代数
- 5 种基本的关系代数运算:并、差、笛卡儿积、投影和选择
- 扩展的关系代数运算:交(Intersection)、连接(Join)、除(Division)、广义投影(Generalized Projection)、外连接(Outer Jion)
- 关系数据库 SQL 语言
- SQL 数据定义
- 1. 创建表 CREATE TABLE
- 2. 修改表 LTER TABLE 和删除表 DROP TABLE
- 3. 索引建立与删除
- 4. 视图创建与删除
- SQL 数据查询 —— 子查询与聚集函数、分组查询、字符串查询 LIKE、视图查询
- SQL 数据更新 —— 增删改
- SQL 访问控制 —— 授权 GRANT、收回权限 REVOKE
- SQL 连接操作
- Cross Join 交叉连接
- Inner Join 内部连接
- Left Join 左连接
- Right Join 右连接
- Full Outer Join 全外连接
- Self Join 自连接
- SET OPERATION 集合运算
- 关系数据库的规范化 —— 1NF、2NF、3NF、BCNF
- 1. 第一范式(1NF):消除重复记录(每个分量都不可再分)
- 2. 第二范式(2NF):消除部分依赖(非主属性必须依赖于整个主键而不是一部分)
- 3. 第三范式(3NF):消除传递依赖(非主属性不应该依赖于其他非主属性)
- 4. Boyce-Codd 范式(BCNF):3NF 的最强形式(对每个 X → Y 中的 X 必须是超键)
- 5. 第四范式(4NF):消除多值依赖
- 第六范式(5NF):消除连接依赖
- 数据库的控制功能
- 事务管理
- 数据库的备份与恢复
- 并发控制
- 并发控制技术 —— 封锁
基本概念
数据库管理系统 (DataBase Management System, DBMS)主要实现对共享数据有效地组织、管理和存取,故 DBMS 应具有以下六个方面的功能。
- 数据定义:DBMS 提供数据定义语言(Data Definition Language, DDL),用户可以对数据库的结构进行描述,包括外模式、模式和内模式的定义、数据库的完整性定义等。
- 数据库操作:DBMS 向用户提供数据操纵语言(Data Manipulation Language,DML),实现对数据库中数据的基本操作,例如检索、插入、修改和删除。
- 数据库运行管理:数据库在运行期间多用户环境下的并发控制、安全性检查和存取控制、完整性检查和执行、运行日志的组织管理、事务管理和自动恢复等是DBMS 的重要组成部分。
- 数据的组织、存储和管理:DBMS 分类组织、存储和管理各种数据,包括数据字典、用户数据和存取路径等。要确定以何种文件结构和存取方式在存储级上组织这些数据,提高效率。
- 数据库的建立和维护:数据库的建立和维护包括数据库的初始建立、数据的转换、数据库的转储和恢复、数据库的重组和重构、性能监测和分析等。
- 其他功能包括:DBMS 的网络通信功能,一个DBMS 与另一个 DBMAS 或文件系统的数据转换功能。
数据库的三级模式结构
数据的存储结构也各不相同,但体系结构基本上都具有相同的特征,采用 “三级模式和两级映像”,
- 概念模式也称模式,它是数据库中 全部数据的逻辑结构和特征的描述,由若干个概念记录类型组成,只涉及型的描述,不涉及具体的值。
- 概念模式的一个具体值称为模式的一个实例,同一个模式可以有很多实例。
- 概念模式反映的是数据库的结构及其联系,所以是相对稳定的;而实例反映的是数据库某一时刻的状态,所以是相对变动的。
- 概念模式不仅要描述概念记录类型,还要描述记录间的联系、操作以及数据的完整性和安全性等要求。但是,概念模式不涉及存储结构、访问技术等细节。只有这样,概念模式才算做到了“物理数据独立性”。
- 外模式也称用户模式或子模式,是用户与数据库系统的接口,是用户用到的那部分数据的描述。它由若干个外部记录类型组成。
- 用户使用数据操纵语言对数据库进行操作,实际上是对外模式的外部记录进行操作。
- 程序员不必关心概念模式,只与外模式发生联系,按外模式的结构存储和操纵数据。
- 内模式也称存储模式,是数据物理结构和存储方式的描述,是数据在数据库内部的表示方式,定义所有的内部记录类型、索引和文件的组织方式,以及数据控制方面的细节。
- 例如,记录的存储方式是顺序存储,按照 B 树结构存储,还是 Hash 方法存储。
数据库系统在三级模式之间提供了两级映像:模式/内模式映像、外模式/模式映像。正因为这两级映像保证了数据库中的数据具有较高的逻辑独立性和物理独立性。
- 数据的物理独立性是指当数据库的内模式发生改变时,数据的逻辑结构不变。
- 数据的逻辑独立性是指用户的应用程序与数据库的逻辑结构是相互独立的。数据的逻辑结构发生变化后,用户程序也可以不修改。
数据模型
- 概念数据模型也称信息模型,是 按用户的观点对数据和信息建模;是现实世界到信息世界的第一层抽象,强调其语义表达功能,易于用户理解;是 用户和数据库设计人员交流的语言,主要用于数据库设计。这类模型中最著名的是实体-联系模型,简称 E-R 模型。
- 基本数据模型。它是 按计算机系统的观点对数据建模,是现实世界数据特征的抽象,用于 DBMS 的实现。基本的数据模型有层次模型、网状模型、关系模型和面向对象模型(Object Oriented Model)。
E-R 模型
- 电影院里 一个座位只能坐一个观众,因此观众与座位之间是一个 一对一1:1 的联系。
- 若 一个职工只能属于一个部门,那么这两个实体集之间应是一个 一对多 1:n 的联系。
- 若 一个职工可以参加多个项目,一个项目可以有多个职工参加,那么这两个实体集之间应是一个 多对多m:n 的联系。
- 供应商为多个项目供应多种零件,每个项目可用多个供应商供应的零件,每种零件可由不同的供应商供应,即供应商 Supp、项目 Proj 和零件 Part 之间 多对多对多 (r:n:m)的联
系。 - 一个特护病房有多个病人和多个医生,一个医生只负责一个病房,一个病人只属于一个病房,即病房、病人和医生之间 一对多对多(1:n:m) 的联系。
关系模型
关系数据库系统采用关系模型作为数据的组织方式,在关系模型中用表格结构表达实体集以及实体集之间的联系,其最大特色是描述的一致性。关系模型是由若干个关系模式组成的集合。一个关系模式相当于一个记录型,关系是一个实例,也是一张表。
教学数据库的 4 个关系模式如下:
关系模式中有下划线的属性是主码属性。
各种键
超键:在关系模式中,可以 唯一标识一个元组的属性集 称为超键(Super Key)。
student(Sno, Sname, Sage, Ssex)
中,只有包含Sno
的属性集合才能是超键,因为如果不包含Sno
,可能会出现同名、同性别的人,也可能出现同岁的人,所以在上面的关系模式中只有通过学号才能找到某个特定的学生。因此上述关系模式中只有包含学号的属性集才能称之为超键,如(Sno)
、(Sno, Sname)
、(Sno, Sname, Sage)
等。
候选键:在关系模式中,能 唯一标识元组并且不含多余属性的属性集 称为候选键(Candidate Key)。
student(Sno, Sname, Sage, Ssex)
中,如果没有重名的学生,Sname
也可以当成是候选键,这里可以看出候选键是一种特殊的超键,即把超键中多余的属性删除就可以叫做候选键。所以(Sno)
、(Sname)
可以叫做候选键。
主键:在关系模式中的 若干个候选键中,随意指定一个 作为关键字,此关键字即为主键(Primary Key)。
student(Sno, Sname, Sage, Ssex)
,在候选键的基础上任意选择一个作为主键如(Sno)
,同时衍生出复合主键和联合主键 ,假设我们没有学号字段,如果可以通过姓名,年龄,性别一同找到某个特定的学生,那么就称(name, age, sex)
为复合主键,全部由主键构成的称为联合主键。
外键:可以把一张表的数据与另一张表关联起来,这种列称为外键(Foreign Key)。
student(Sno, Sname, Sage, Ssex,SCredit)
和score(Sno, Tno, Sco)
,外键是建立在两个关系模式中的,Sno
是表score
的外键,他把两个表关联起来了。
完整性约束
关系的完整性共分为三类:实体完整性、参照完整性(也称引用完整性)和用户定义完整性。
- 实体完整性(Entity Integrity)。规定基本关系 R 的 主属性不能取空值。
- 参照完整性(Referential Integrity)。现实世界中的实体之间往往存在某种联系,在关系模型中实体及实体间的联系是用关系来描述的,这样自然就存在着关系与关系间的引用。
-
-
员工关系中的“部门号”属性取值要参照部门关系的“部门号”属性取值。
-
- 用户定义完整性(User Defined Integrity)。用户定义完整性就是针对某一具体的关系数据库的约束条件,反映某一具体应用所涉及的数据必须满足的语义要求,由应用的环境决定。
- 例如,银行的用户账户规定必须大于等于100000、小于999999。
关系代数
5 种基本的关系代数运算:并、差、笛卡儿积、投影和选择
- 投影运算 是从 关系的垂直方向 进行运算,在关系 R 中选出若干属性列 A 组成新的关系,记作 π A ( R ) \pi_A(R) πA(R)。
- 选择运算 是从 关系的水平方向 进行运算,是从关系 R 中选择满足给定条件的诸元组,记作 σ F ( R ) \sigma_F(R) σF(R)。
- F F F 中的运算对象是属性名(或列的序号)或常数,运算符、算术比较符( < < <、 ≤ ≤ ≤、 > > >、 ≥ \ge ≥、 ≠ ≠ =)和逻辑运算符( ∧ \wedge ∧、 ∨ \vee ∨、 ¬ ¬ ¬)。
- 例如, σ 1 ≥ 6 ( R ) \sigma_{1 \ge 6}(R) σ1≥6(R) 表示选取 R 关系中第 1 个属性值大于等于第 6 个属性值的元组; σ 1 ≥ ′ 6 ′ ( R ) \sigma_{1 \ge '6'}(R) σ1≥′6′(R) 表示选取 R 关系中第 1 个属性值大于等于 6 的元组。
选择题,为什么做题总比别人慢呢?
- 我做题时候:先 R 和 S 进行笛卡尔积,选择 R.A 比 S.B 大的元组(只有 10 > 7),投影出来 R.A,S.B 和 S.C 三列,应该只有
(10, 7, 6)
才对,看选项, A、C、D 肯定错,B 也错了呀,S.C 哪有 11 呀?。。。- 聪明人做题时候,投影出来的第一列的值要大于第二列的值,所以 A、C、D 错,选 B,走人!
- 正确答案就是 B。看出和聪明人的差距了吗?!别问我是怎么知道聪明人咋做的,非要问的话,我就是聪明人!
扩展的关系代数运算:交(Intersection)、连接(Join)、除(Division)、广义投影(Generalized Projection)、外连接(Outer Jion)
- 关系 R 与 S 具有相同的关系模式,关系 R 与 S 的交 是由 属于 R 同时又属于 S 的元组构成的集合,记作 R ∩ S R \cap S R∩S。
- 除运算 是 同时从关系的水平方向和垂直方向进行运算。用于找出“在关系 R 中,与另一个关系 S 的所有元组都相关联”的那些元组。
- 广义投影运算 允许在 投影列表中使用算术运算,实现了对投影运算的扩充。
- 连接指的是自然连接,是等值连接。
- 外连接运算是连接运算的扩展,可以处理由于连接运算而缺失的信息。外连接运算有 3 种,即左外连接、右外连接和全外连接。
关系数据库 SQL 语言
SQL 语言支持关系数据库的三级模式结构,其中,视图对应外模式、基本表对应模式、存储文件对应内模式。
SQL 语言功能极强,完成核心功能只用了 9 个动词,包括以下 4 类:
- 数据查询:SELECT。
- 数据定义:CREATE、DROP、ALTER。
- 数据操纵:INSERT、UPDATE、DELETE。
- 数据控制:GRANT、REVORK。
SQL 数据定义
基本表和视图都是表,所不同的是基本表是实际存储在数据库中的表,视图是虚表,是从基本表或其他视图中导出的表。数据库中只存放视图的定义,不存放视图的数据。
SQL 的数据定义包括对表、视图、索引的创建和删除。
1. 创建表 CREATE TABLE
创建表:
列级完整性约束条件有 NULL
(空)和 UNIQUE
(取值唯一),如 NOT NULL UNIQUE
表示取值唯一,不能取空值。
PRIMARY KEY(Sno)
已经定义了 Sno 为主码,所以Sno CHAR(5) NOT NULL UNIQUE
语句中的NOT NULL UNIQUE
可以省略。FOREIGN KEY(Sno) REFERENCES S(Sno)
定义了在 SP 关系中 Sno 为外码,其取值必须来自S 关系的 Sno 域。同理,在 SP 关系中 Pno 也定义为外码。
2. 修改表 LTER TABLE 和删除表 DROP TABLE
修改表:
- 例如,向“供应商”表 S 增加 Zap “邮政编码”可用如下语句:
ALTER TABLE S ADD Zap CHAR(6)
。不论基本表中原来是否已有数据,新增加的列一律为空。 - 又如,将 Status 字段改为整型可用如下语句:
ALTER TABLE S MODIFY Status INT
。
删除表:
例如执行 DROP TABLE Student
,此后关系 Student 不再是数据库模式的一部分,关系中的元组也无法访问。
3. 索引建立与删除
索引分为聚集索引和非聚集索引。聚集索引 是指索引表中索引项的顺序与表中记录的物理顺序一致的索引。
索引创建:
- 次序:可选 ASC(升序)或 DSC(降序),默认值为 ASC。
- UNIQUE:表明此索引的每一个索引值只对应唯一的数据记录。
- CLUSTER:表明要建立的索引是聚簇索引,意为索引项的顺序是与表中记录的物理顺序一致的索引组织。
索引删除:
例如执行 DROP INDEX StudentIndex
,此后索引 StudentIndex 不再是数据库模式的一部分。
4. 视图创建与删除
视图不是真实存在的基本表,而是一个虚拟表,视图所对应的数据并不实际地以视图结构存储在数据库中,而是存储在视图所引用的表中。
视图创建:
在 视图的创建 中必须遵循以下规定,
- 子查询 可以是任意复杂的 SELECT 语句,但 通常不允许含有
ORDER BY
子句和DISTINCT
短语。 WITH CHECK OPTION
表示对UPDATE
、INSERT
、DELETE
操作时保证更新、插入或删除的行 满足视图定义中的谓词条件(即 子查询中的条件表达式)。- 组成视图的属性列名或者全部省略或者全部指定。如果省略属性列名,则隐含该视图由
SELECT
子查询目标列的主属性组成。
由于 CS-STUDENT 视图使用了WITH CHECK OPTION
子句,因此,对该视图进行修改、插入操作时 DBMS 会自动加上SD='CS'
的条件,保证该视图中只有计算机系的学生。
视图删除:
SQL 数据查询 —— 子查询与聚集函数、分组查询、字符串查询 LIKE、视图查询
SQL 的数据操纵功能包括 SELECT(查询)、INSERT (插入)、DELETE(删除)和 UPDATE (修改)这 4 条语句。
SQL 查询中的 子句顺序为 SELECT
、FROM
、WHERE
、GROUP BY
、HAVING
和 ORDER BY
。其中,SELECT
、FROM
是必需的,HAVING
条件子句只能与 GROUP BY
搭配起来使用。
SELECT
子句对应的是关系代数中的投影运算,用来列出查询结果中的属性。其输出可以是列名、表达式、集函数(AVG
、COUNT
、MAX
、MIN
、SUM
),DISTINCT
选项可以保证查询的结果集中不存在重复元组。FROM
子句对应的是关系代数中的笛卡儿积,它列出的是 表达式求值过程中需扫描的关系,即在FROM
子句中出现多个基本表或视图时,系统 首先执行笛卡儿积操作。WHERE
子句对应的是关系代数中的选择谓词。
- SQL 简单查询是找出关系中满足特定条件的元组,这些查询与关系代数中的选择操作类似。简单查询只需要使用 3 个保留字,即
SELECT
、FROM
和WHERE
。 - 若查询涉及两个以上的表,则称为连接查询。
- 子查询也称嵌套查询。嵌套查询是指一个
SELECT-FROM-WHERE
查询块可以嵌入另一个查询块之中。在 SQL 中允许多重嵌套。
聚集函数 是 以一个值的集合为输入,返回单个值的函数。SQL 提供了 5 个预定义聚集函数:平均值AVG
、最小值MIN
、最大值MAX
、求和SUM
以及计数COUNT
。
使用ANY
和ALL
谓词必须同时使用比较运算符,其含义及等价的转换关系如表所示。用聚集函数实现子查询通常比直接用ALL
或ANY
查询效率要高。
注意,这里 不等于用<>
。
- 分组查询:在
WHERE
子句后面加上GROUP BY
子句可以对元组进行分组,保留字GROUP BY
后面跟着一个分组属性列表。
假如元组在分组前按照某种方式加上限制,使得不需要的分组为空,在GROUP BY
子句后面跟一个HAVING
子句即可。
- 空值在任何聚集操作中被忽视。它对求和、求平均值和计数都没有影响。它也不能是某列的最大值或最小值。例如,
COUNT(*)
是某个关系中所有元组数目之和,但COUNT(A)
却是 A 属性非空的元组个数之和。NULL
值又可以在分组属性中看作是一个一般的值。例如,在SELECT A, AVG(B) FORM R
中,当 A 的属性值为空时,就会统计A=NULL
的所有元组中 B 的均值。
需要注意的是,一个工程项目可能用了同一个供应商的多种零件,因此,在统计供应商数的时候需要加上DISTINCT
,以避免重复统计导致错误的结果。例如,按工程号Jno='J1'
分组,其结果如表所示。如果不加DISTINCT
,统计的结果数为 7;而加了DISTINCT
,统计的结果数为 5。
-
更名运算:
Old-name AS new-name
,AS
子句既可出现在SELECT
子句,也可出现在FROM
子句中。 -
字符串操作:使用操作符
LIKE
的模式匹配。使用两个特殊的字符来描述模式:%
匹配任意字符串;_
匹配任意一个字符。模式是大小写敏感的。
为了使模式中包含特殊模式字符(即 %
和 _
),在 SQL 中允许使用 ESCAPE
关键词来定义转义符。转义符紧靠着特殊字符,并放在它的前面,表示该特殊字符被当成普通字符。例如,在 LIKE
比较中使用 ESCAPE
关键词来定义转义符,例如使用反斜杠 \
作为转义符。
7. 视图的查询:当查询视图表时,系统先从数据字典中取出该视图的定义,然后将定义中的查询语句和对该视图的查询语句结合起来,形成一个修正的查询语句。
对上例修正之后的查询语句为:SELECT Sno, Age FORM Student WHERE SD='CS' AND Age<20
。
SQL 数据更新 —— 增删改
插入语句:
删除语句:
修改语句:
使用视图可以更新数据记录,但应该注意的是,更新的只是数据库中的基表。
SQL 访问控制 —— 授权 GRANT、收回权限 REVOKE
DBMS 数据控制应具有以下功能,
- 通过
GRANT
和REVOKE
将授权通知系统,并存入数据字典。 - 当用户提出请求时,根据授权情况检查是否执行操作请求。
授权语句:
PUBLIC
:接受权限的用户可以是单个或多个具体的用户,PUBLIC
参数可将权限赋给全体用户。WITH GRANT OPTION
:若指定了此子句,那么 获得了权限的用户还可以将权限赋给其他用户。
收回权限语句:
SQL 连接操作
在 SQL 中,连接操作 用于根据表之间的相关列组合两个或多个表中的行。它允许我们在单个查询中检索来自多个表的数据,这在我们需要处理存储在不同的表中的相关数据时特别有用。
这就像把拼图块放在一起来看整体画面。使用 在两个表中具有匹配值的列来连接它们,不同类型的连接提供了不同的方法来组合信息。
为什么需要多个表来存储相关数据?
在数据库中使用多个表来存储相关数据有助于组织信息,减少冗余,确保数据准确性,并使管理和检索特定细节变得更加容易。这种方法促进了效率、可扩展性以及更好的数据访问和变更控制。
想象一下数据库是一个大型的信息组织存储系统。假设我们正在存储关于学校的数据。
- 我们可以将所有关于学生、班级、教师和科目的详细信息放在一个巨大的列表中,但那会很快变得混乱和令人困惑。
- 相反,我们为不同类型的信息使用单独的文件夹(表)。一个文件夹包含学生姓名和详细信息,另一个包含班级信息,等等。这些文件夹通过共同的信息片段(如学生 ID)相互连接。
因为这种分离:- 更容易更新:如果一个学生改变了他们的地址,我们只需要在一个地方更新它,所有他们的记录都会自动更新。
- 减少错误:更少的机会以不同的方式输入相同的信息。
- 保持快速:在较小、有序的文件夹中搜索和排序更快。
- 节省空间:我们不会为每个相关事物重复相同的信息(例如,每个学生所在的班级名称)。
Cross Join 交叉连接
SQL 中的 CROSS JOIN 就像 在两个数据集之间创建所有可能的组合,结果是一个笛卡尔积。它将第一个表中的每一行与第二个表中的每一行组合,创建一个包含所有可能行对的新表。
#CROSS JOIN
select t1.name, t2.course_id
from table1 t1 cross join table2 t2
Inner Join 内部连接
这种连接类型 只返回两个表中具有匹配值的行。具有不匹配值的行将被排除在结果之外。SQL 中的 INNER JOIN 就像将两个完美契合的拼图块组合在一起。它是将两个表中的数据结合起来的方式,只显示它们之间的匹配行。
#Inner Join
select t1.name, t2.order_id
from table1 t1 inner join table2 t2
on t1.order_id = t2.order_id
Left Join 左连接
SQL 中的 LEFT JOIN 就像将两组数据结合起来,同时 保留左表的所有行,而只保留右表中匹配的行。如果在右表中没有匹配项,结果仍然会包含左表的行,但在右表的列中将包含 NULL 值。
#Left Join
select t1.name, t2.price
from table1 t1 left join table2 t2
on t1.order_id = t2.order_id
Right Join 右连接
SQL 中的 RIGHT JOIN 与 LEFT JOIN 类似,但表的角色被颠倒了。它 保留右表的所有行,而只保留左表中匹配的行。如果在左表中没有匹配项,结果仍然会包含右表的行,但在左表的列中将包含 NULL 值。
#Right Join
select t1.name, t2.price
from table1 t1 right join table2 t2
on t1.order_id = t2.order_id
Full Outer Join 全外连接
个全外连接是一种连接类型,它结合了左连接和右连接的结果。它返回两个表中的所有行,在存在匹配的情况下返回匹配行,在没有匹配的情况下用空值填充。但是,需要注意的是,MySQL 没有像其他一些数据库系统那样的内置全外连接运算符。相反,你可以使用左连接和并集的组合来模拟全外连接。
#Left Join
select t1.name, t2.price
from table1 t1 left join table2 t2
on t1.order_id = t2.order_id
union
#Right Join
select t1.name, t2.price
from table1 t1 right join table2 t2
on t1.order_id = t2.order_id
Self Join 自连接
SQL 中的自连接是一种连接类型,其中 表与自身进行连接。当表包含层次结构或相关数据时,它很有用,并且我们希望根据某些条件比较或组合同一表中的行。
要执行自连接,我们 使用表别名在同一查询中创建同一表的两个不同的“视图”。这允许你将表视为如果你有两个单独的实例,然后你可以使用它们来建立行之间的关系。
#Self Join
select t1.name, t2.name as 'secret_santa'
from table1 t1 join table1 t2
on t1.assigned_color = t2.color
SET OPERATION 集合运算
SQL 中的集合运算指的是根据特定条件或标准将多个 SELECT 查询的结果组合成一个结果集。
虽然集合运算通常不被称作“连接”,但它们允许我们以类似于连接的方式组合和操作数据。集合运算包括 UNION、INTERSECT 和 EXCEPT(在某些数据库中也称为 MINUS)。
- UNION:UNION 操作 将两个或多个 SELECT 查询的结果组合成一个结果集,并删除重复项。每个 SELECT 查询必须具有相同数量的列,并且列的数据类型必须兼容。
SELECT column1 FROM table1
UNION
SELECT column2 FROM table2;
- INTERSECT:INTERSECT 操作 返回两个或多个 SELECT 查询结果中出现的公共行。与 UNION 类似,列的数量及其数据类型必须匹配。
SELECT column1 FROM table1
INTERSECT
SELECT column1 FROM table2;
- EXCEPT(MINUS):EXCEPT 操作 返回第一个 SELECT 查询结果中出现的行,但不在第二个 SELECT 查询结果中出现的行。它与找出两个集合之间的差集类似。
SELECT column1 FROM table1
EXCEPT
SELECT column1 FROM table2;
关系数据库的规范化 —— 1NF、2NF、3NF、BCNF
1. 第一范式(1NF):消除重复记录(每个分量都不可再分)
定义:若关系模式 R 的每一个分量是不可再分的数据项,则关系模式 R 属于第一范式。
如果一个表满足以下条件,则它处于 1NF:
- 所有列都包含 原子值(即不可分割的值)。
- 每一行都是唯一的(即,没有重复的行)。
- 每一列都有一个唯一的名称。
- 存储数据的 顺序并不重要。
从表9-8 可以看出,每一个分量都是不可再分的数据项,所以是 1NF 的。
但是,1NF 存在以下 4 个问题,冗余度大、引起修改操作的不一致性、插入异常、删除异常。
2. 第二范式(2NF):消除部分依赖(非主属性必须依赖于整个主键而不是一部分)
如果一个关系满足 1NF 的条件,并且此外不存在部分依赖,则它处于 2NF。这意味着 每个非主属性必须依赖于整个主键,而不仅仅依赖于其一部分。
示例:对于复合键
(StudentID, CourseID)
,如果StudentName
仅依赖于StudentID
而不是依赖于整个键,则违反了 2NF。
为了规范化,将StudentName
移动到一个单独的表中,使其仅依赖于StudentID
。
3. 第三范式(3NF):消除传递依赖(非主属性不应该依赖于其他非主属性)
如果一个关系满足 2NF,并且没有传递依赖,那么它就在 3NF 中。换句话说,非主属性不应该依赖于其他非主属性。
示例:考虑一个包含
(StudentID, CourseID, Instructor)
的表。如果Instructor
依赖于CourseID
,而CourseID
依赖于StudentID
,那么Instructor
间接依赖于StudentID
,这违反了 3NF。
为了解决这个问题,将Instructor
放在一个单独的表中,并通过CourseID
进行链接。
4. Boyce-Codd 范式(BCNF):3NF 的最强形式(对每个 X → Y 中的 X 必须是超键)
BCNF 是 3NF 的一个更严格的版本,其中对于每个非平凡的函数依赖(X → Y
),X
必须是超键(即表中的唯一记录标识符)。
示例:如果一个表有一个依赖关系
(StudentID, CourseID) → Instructor
,但StudentID
和CourseID
都不是超键,那么它就违反了 BCNF。
为了将其转换为 BCNF,需要分解表,以便每个决定因素都是候选键。
5. 第四范式(4NF):消除多值依赖
如果一个表在 BCNF 中并且没有多值依赖,则它处于 4NF 中。多值依赖发生在一个属性决定另一个属性,并且这两个属性都独立于表中的所有其他属性。
示例:考虑一个包含
(StudentID,Language,Hobby)
属性的关系表。如果一个学生可以有多个爱好和语言,就存在多值依赖。
为了解决这个问题,需要将表拆分为单独的“语言”和“爱好”表。
第六范式(5NF):消除连接依赖
当一个表满足 4NF 并且所有连接依赖都被消除时,就达到了 5NF。这种范式确保每个表都被完全分解为更小的、逻辑上连接的表,同时不丢失信息。
示例:如果一个表包含
(StudentID,Course,Instructor)
并且存在一种依赖关系,需要所有这些列的组合来表示特定的关系,那么可以将它们拆分为更小的表以消除冗余。
数据库的控制功能
事务管理
事务是一个操作序列,这些操作“要么都做,要么都不做”,是数据库环境中不可分割的逻辑工作单位。事务和程序是两个不同的概念,一般一个程序可包含多个事务。
SQL 语言中,事务定义的语句有以下三条,
BEGIN TRANSACTION
:事务开始。COMMIT
:事务提交。该操作表示事务成功地结束,它将通知事务管理器该事务的所有更新操作现在可以被提交或永久地保留。ROLLBACK
:事务回滚。该操作表示事务非成功地结束,它将通知事务管理器出故障了,数据库可能处于不一致状态,该事务的所有更新操作必须回滚或撤销。
事务具有 原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability)。这 4 个特性也称 事务的 ACID 性质。
- 原子性。事务是原子的,要么都做,要么都不做。
- 一致性。事务执行的结果必须保证数据库从一个一致性状态变到另一个一致性状态。因此,当数据库只包含成功事务提交的结果时,称数据库处于一致性状态。
- 隔离性。事务相互隔离。当多个事务并发执行时,任一事务的更新操作直到其成功提交的整个过程,对其他事务都是不可见的。
- 持久性。一旦事务成功提交,即使数据库崩溃,其对数据库的更新操作也将永久有效。
数据库的备份与恢复
在数据库的运行过程中,难免会出现计算机系统的软、硬件故障,这些故障会影响数据库中数据的正确性,甚至破坏数据库,使数据库中的全部或部分数据丢失。
数据库中的 4 类故障是 事务内部故障、系统故障、介质故障及计算机病毒。
- 事务内部故障。
- 事务内部的故障有的可以通过事务程序本身发现。例如,银行转账事务,将账户 A 的金额转 X 到账户 B,此时应该将账户 A 的余额 -X,将账户 B 的余额 +X。如果账户 A 的余额不足,那么,两个事务都不做,否则都做。
- 但有些是非预期的,不能由事务程序处理,例如运算溢出、并发事务发生死锁等。
- 系统故障。通常称为软故障,是指 造成系统停止运行的任何事件,使得系统要重新启动,例如 CPU 故障、操作系统故障和突然停电等。
- 介质故障。通常称为硬故障,如磁盘损坏、磁头碰撞和瞬时强磁干扰。此类故障发生的几率小,但破坏性最大。
- 计算机病毒。计算机病毒是一种人为的故障和破坏,是在计算机程序中插入的破坏,计算机功能或者数据可以繁殖和传播的一组计算机指令或程序代码。
因此,数据库的关键技术在于建立冗余数据,即备份数据。
建立冗余数据的方法是进行数据转储和登记日志文件。数据的转储分为静态转储和动态转储、海量转储和增量转储、日志文件。
- 静态转储和动态转储。静态转储是指在转储期间不允许对数据库进行任何存取、修改操作;动态转储是在转储期间允许对数据库进行存取、修改操作。因此,转储和用户事务可并发执行。
- 海量转储和增量转储。海量转储是指每次转储全部数据;增量转储是指每次只转储上次转储后更新过的数据。
- 日志文件。在事务处理的过程中,DBMS 把事务开始、事务结束以及对数据库的插入、删除和修改的每一次操作写入日志文件。一旦发生故障,DBMS 的恢复子系统利用日志文件撤销事务对数据库的改变,回退到事务的初始状态。
如何在系统出现故障后能够及时地使数据库恢复到故障前的正确状态,就是数据库恢复技术。
事务恢复有以下 3 个步骤。
- 反向扫描文件日志(即从最后向前扫描日志文件),查找该事务的更新操作。
- 对事务的更新操作执行逆操作。
- 继续反向扫描日志文件,查找该事务的其他更新操作,并做同样的处理,直到事务的开始标志。
许多 DBMS 提供数据库镜像功能用于数据库恢复。数据库镜像是通过复制数据实现的,但频繁地复制数据会降低系统的运行效率。在实际应用中往往对关键的数据和日志文件镜像。
并发控制
并发操作带来的数据不一致性有三类:丢失修改、不可重复读和读脏数据。
- 丢失修改:T1、T2 两个事务都是对 A 的值进行减 1 操作并且都执行成功,但 A 中的值却只减了 1。原因在于 T1 事务对数据库的修改被 T2 事务覆盖而丢失了,破坏了事务的隔离性。
- 不可重复读。事务 T1 读取 A、B 的值后进行运算,事务 T2 在 6 时刻对 B 的值做了修改以后,事务 T1 又重新读取 A、B 的值再运算,同一事务内对同一组数据的相同运算结果不同,显然与事实不相符。同样是事务 T2 干扰了事务 T1 的独立性。
- 读脏数据。事务 T1 对数据 C 修改之后,在时刻事务 T2 读取修改后的 C 值做处理,之后事务 T1 回滚,数据 C 恢复了原来的值,事务 T2 对 C 所做的处理是无效的,它读的是被丢掉的垃圾值。
并发控制技术 —— 封锁
基本封锁的类型有排它锁(简称 X 锁或写锁)和共享锁(简称 S 锁或读锁)。
- 排它锁。若事务 T 对数据对象 A 加上 X 锁,则 只允许 T 读取和修改 A,其他事务都不能再对 A 加任何类型的锁,直到 T 释放 A 上的锁。
- 共享锁。若事务 T 对数据对象 A 加上 S 锁,则 只允许 T 读取 A,但不能修改 A,其他事务只能再对 A 加 S 锁,直到 T 释放 A 上的 S 锁。这就保证了 其他事务可以读 A,但在 T 释放 A 上的 S 锁之前不能对 A 进行任何修改。
两段封锁协议,是指所有事务必须分两个阶段对数据项加锁和解锁。即事务分两个阶段,第一阶段是获得封锁,事务可以获得任何数据项上的任何类型的锁,但不能释放;第二阶段是释放封锁,事务可以释放任何数据项上的任何类型的锁,但不能申请。