北航软院数据库课程笔记
概论
数据库相关概念
- 信息:是影响动态系统的状态的事件
- 数据:用于记录信息;对客观事物进行记录并可以鉴别的符号
- 数据是信息的载体;信息是数据的解译,是组织起来的数据。数据本身是无意义的,数据+解释=信息。
- 信息科技需要解决数据存储、数据传输和数据处理这三个核心问题。
- 数据管理的任务
- 数据存储
- 数据维护
- 数据查询
- 数据安全等
- 数据库:长期储存在计算机内、有组织的、可共享的大量数据的集合。
- 数据库管理系统DBMS:管理数据库的一种大型复杂软件系统
- 数据定义
- 数据组织、存储、管理等功能
- 数据库系统DBS:基于数据库建立的一种信息系统
- 通常由应用程序、数据库、数据库管理系统和用户组成
- 数据库管理发展历史:手工处理→文件系统→数据库系统
- 手工处理阶段数据不保存,没有对数据进行管理的软件系统,一组数据对应于一个程序,数据面向应用
- 文件系统阶段,数据可以长期保存,文件系统可以对数据的存取进行管理,程序与数据之间有一定独立性;但是数据冗余度大,数据独立性低,数据一致性差。
- 数据库系统阶段,实现了整体数据的结构化、数据共享、数据独立性、方便的用户接口。
- 数据独立性:指数据库中的数据与应用程序之间不存在依赖关系,而是相互独立的
- 物理独立性:修改数据库的物理存储模式,而不必重写应用程序
- 逻辑数据独立性:修改数据库的逻辑模式,而不必重写应用程序
数据库结构
- 模式– – 逻辑层
- 模式:数据库中全体数据的逻辑结构和特征的描述
- 一个数据库只有一个模式
- 模式是数据库系统模式结构的中间层
- 外模式– – 用户层
- 外模式:数据库用户使用的局部数据的逻辑结构和特征的描述
- 外模式:介于模式和应用之间,一个数据库可以有多个外模式
- 内模式– – 物理层
- 内模式:也称存储模式,是数据物理结构和存储方式的描述;是数据在数据库内部的表示方式。
- 一个数据库只有一个内模式。
- 外模式/模式映象
- 将外模式映射为概念模式,从而支持数据概念视图向外部视图的转换,保证数据的逻辑独立性:模式改变时修改有关的外模式/模式映像即可,不用修改外模式和应用程序。
- 实现手段:视图(view)
- 模式/内模式映象
- 定义了数据全局逻辑结构与存储结构之间的对应关系
- 保证数据的物理独立性
- 数据库体系结构
- 集中式
- 客户–服务器式
- 分布式
- 并行式
- 云数据库
数据模型
模型是对现实世界的抽象。
- 概念数据模型:对现实世界的第一层抽象;
- 逻辑数据模型:直接面向数据库的逻辑结构,是对现实世界的第二层抽象;是区分不同类型数据库的依据,并在很大程度上决定了数据库的性能和应用范围。
- 物理数据模型:反映数据在存储介质上的组成机构,并描述了访问机制:如何表达记录结构、记录顺序和访问路径等信息。
ER数据模型
一种概念数据模型。
三个基本元素:
-
实体:客观存在并可以相互区分的客观事物或抽象事件。
-
属性:实体所具有的某一特征;一个实体可由若干个属性来刻画。
-
域:属性的取值范围。
-
单值属性:每一个特定的实体在该属性上的取值唯一,如学生的学号。
-
多值属性:某特定实体在该属性上有多于一个的取值,如某人的电话号码。
-
键:实体集中能唯一标识实体的属性或属性组。
两个以上属性组成的键称为复合键。
-
-
联系:集合A、B的笛卡尔积A×B的一个子集。
- 联系由一系列的实体间的对应关系所组成。
两种常用的抽象手段:
- 分类
- 聚集
ER图
联系的元:参与联系的实体的个数称为联系的元。
理解的例子自己看ppt吧。
- 约束:对数据库的一种断言,数据库应该保证该断言成立。常见约束:非空约束、唯一值约束…
- 键约束:
- 超键:实体集中的一个或一组属性,可以确定唯一的每一个实体。
- 候选键:某个超键的最小集。
- 主键:某一个候选键。
ER模型建模
建模准则:
-
避免冗余
-
能抽象为属性的,不要抽象为实体
只有在符合以下两个情况之一时才需要把事物抽象为实体:
- 事物至少有一个非键属性
- 事物处于一对多or多对多联系中“多”的一端
其他事物都可以抽象为属性。
-
KISS准则:keep it simple and stupid
-
忠实于用户准则。
设计过程:
- 先设计实体类型:找出逻辑独立的事物,即管理对象。
- 再设计联系类型:确定实体之间相互影响的关系
- 最后为实体和联系确定属性。
逻辑模型
逻辑模型直接与DBMS有关,有严格的形式化定义。
三要素:数据结构、数据操作和数据约束
概述
-
关系模型
- 用二维表格结构来表示实体以及实体之间联系的模型
- 只有一个概念:关系
-
关系数据库
- 支持关系模型的数据库系统
-
关系的定义:笛卡尔积的任意子集(实际中是有意义的子集)
ER模型向关系模型转化
ER模型向关系模型的转换,实际上就是把ER图转化成关系模式的集合。
-
将每个实体类型转化为一个关系模式:实体的属性即为关系模式的属性,实体标识符即为关系模式的键
-
将联系类型(二元)转化为关系模型。
- 对于m:n联系
- 对于1:n联系:合并到n段对应的实体关系中。
- 对于1:1关系:与常用实体相合并。
- 对于m:n联系
-
对于三元联系:
- 1:1:1 :联系与其中一个实体集合并
- 1:1:N :联系与N端实体集合并
- 1:M:N :联系转化为独立的关系模式,主键为1端实体集的主键
- M:N:P :联系转化为独立的关系模式,主键为三个实体集的主键的组合。
关系的完整性
-
域完整性:属性值应该符合域的取值范围。
-
实体完整性
关系中应设定主键为记录的唯一性标识。
同时主键中的属性不能取空值。
-
参照完整性
- 外键:与其他表确定联系,一般是另一个表的主键
- 参照完整性规则:外键上的值只能是空值,或等于被参照关系中某个元组的主键值。
- 外键与主键重复?数据库中,主键和外键可以同一个字段吗? - 知乎 (zhihu.com)
-
用户定义的完整性
关系代数
- 关系代数是对关系的查询语言:以对关系的运算表示查询。
- 以关系作为运算对象
- 其操作符设计为在数据库中我们对于关系最常做的操作
- 其运算结果也是一个关系
- 关系代数运算的三个要素:
- 运算对象:关系
- 运算结果:关系
- 运算符:4类
四类关系运算符:
- 集合运算符,涉及行
- 专门的关系运算符,涉及行且涉及列
- 算术比较符,辅助专门的关系运算符进行操作
- 逻辑运算符,辅助专门的关系运算符进行操作

基本运算:
- 集合并、集合差、广义笛卡尔积、选择、投影
- 由基本运算可以推导出其它所有运算
集合运算符运算:略
专门的关系运算:
-
选择
- 选择运算是从指定的关系中选择某些元组形成一个新的关系,被选择的元组是用满足某个逻辑条件来指定的
- (选择几个行,组成新表格)
-
-
投影
- 投影运算对指定的关系进行投影操作,根据该关系分两步产生一个新的关系:
- 选择指定的属性,形成一个可能含有重复行的表格
- 删除重复行,形成新的关系
- (实际上就是选择几个列,去除重复行,组成新表格)
-
- 投影运算对指定的关系进行投影操作,根据该关系分两步产生一个新的关系:
-
连接
-
连接是两个表之间的运算。
-
-
此类连接也被称为θ连接。
-
-
还有一种自然连接,是特殊的等值连接:
根据某一公共列进行连接(所以两表连接前常需要用投影选择有用的列和公共列);连接后公共列会保留。
如果有多个公共列,则这些公共列的值都需要相同。
-
-
除运算
SQL语言
SQL的特点:
- 总和统一
- 高度非过程化
- 面向集合的操作方式
- 以同一种语法结构提供两种使用方法:命令方式or程序方式
- 语言简洁
核心SQL的四个部分:
- 数据定义语言,即SQL DDL。
- 数据查询语言
- 数据操纵语言,即SQL DML,分为插入、删除和修改三种操作
- 数据控制语言,即SQL DCL,包括对基本表和视图的授权、完整性规则的描述、事务控制等内容
查询语言
查询语言的基本结构:
- SELECT 指定要显示的属性列
- FROM 指定查询的对象(基本表或视图)
- WHERE 指定查询条件
- GROUP PY 对查询结果按指定列的值分组,该属性列值相等的元组为一个组
- HAVING 筛选出只有满足指定条件的组
- ORDER BY 对查询结果表按指定列值的升序或降序排序
单表查询
单表查询仅涉及一个表,操作顺序:
- 选择表中若干列
- 选择表中若干元组
- 对查询结果排序
- 使用集函数
- 对查询结果进行分组
例:
查询全体学生的姓名、学号
SELECT Sno,Sname
FROM Student;
查询全体学生的详细信息:
SELECT *
FROM Student;
可以使用*作为通配符。
查询经过计算的值:
-
算术表达式:
SELECT Sname,2024-Sage
-
函数:
SELECT LOWER(Sdept)
用小写字母表示所有系名
-
使用列别名改变查询结果的列标题
SELECT Sname AS NAME
则输出的表标题为
NAME
-
字符串常量
选择表中若干元组:
-
保留重复行:
SELECT ALL Sno FROM SC;
ALL为默认关键字,可以省略。
-
消除取值重复的行
注意
DISRINCT
短语的作用范围是所有目标列查询选修课程的各种成绩:
SELECT DISTINCT Cno,Grade
-
查询满足条件的元组
WHRER
子句:-
比较:
SELECT Sname,Sage FROM Student WHERE Sage < 20;//或 WHERE NOT Sage >=20
-
确定范围:
WHERE Sage BETWEEN 20 AND 23
-
确定集合:
IN <值表>,NOT IN<值表>
值表是用逗号分隔的一组取值。
查询IS、MA、CS系学生的姓名
SELECT Sname,Ssex FROM Student WHERE Sdept IN ( 'IS','MA','CS' );
-
字符串匹配:
格式:
WHERE <Attribute> LIKE <pattern>
<pattern>
中的通配符:
%
:代表任意长度(可以为0)的字符串
_
:代表任意单个字符--例:查询姓刘的学生 select * from student where Sname like '刘%' --查询名字中的第二个字为阳的学生 select * from student where Sname like '_阳%'
当要查询的字符串本身就含有
%
或_
时,要使用ESCAPE ‘<换码字符>’短语对通配符进行转义。
SELECT Cno,Credit FROM Course --! Mysql不能用\作为转义符 WHERE Cname LIKE 'DB\_Design' ESCAPE '\'
对于包含单引号的字符串,在条件表达式中用双引号代替单引号。
-
-
多重条件查询:
用
AND
,OR
,NOT
来连接。 -
涉及空值的查询
Where 语句中的条件表达式有三种可能的计算结果: True,False,或者 UnKnown
任何一个值与NULL进行比较,返回的结果是UnKnown
Where子句对被查询表中每一条记录进行条件表达式的计算,只有在计算结果为True时当前记录才会被选中
三值逻辑计算中,TRUE = 1, FALSE = 0, and UNKNOWN = ½
测试是否空值需用
IS NULL
或IS NOT NULL
,不能用= NULL
替代。-
对查询结果进行排序
使用ORDER BY子句
- 升序:ASC(默认),排序列为空值的元组最后显示
- 降序:DESC,排序列为空值的元组最先显示
例:
ORDER BY Id DESC,Age ASC
-
聚集和分组
使用集函数
可以使用集函数,对指定的列进行聚合运算
- 计数COUNT
- 求和SUM
- 计算平均值AVG
- 求MAX,MIN
使用格式:
[运算类型] ([DISTINCT/ALL] <列名>|*),其中ALL为缺省值
例:
查询学生总人数:
SELECT COUNT(*)
FROM Student;
查询选修了课程的学生人数(可能有重修):
SELECT COUNT(DISTINCT Sno)
FROM SC;
集函数中的NULL不加入计算,也不会成为最大最小值;
但是如果列中没有非空值,则集函数结果会返回空值。
对查询结果进行分组
使用GROUP BY
子句进行分组。
分组方法:按指定的一列或多列值分组,值相等的为一组。
未对查询结果分组时,集函数将作用于整个查询结果;
对查询结果分组后,集函数将分别作用于每个组。

使用HAVING
短语筛选出最终输出结果。
having
子句中出现的列只能是在group by
子句或集函数中出现的列。

*注意WHERE子句中不能使用集函数。
使用group by
子句后,select
子句的列名列表中只能出现分组属性和集函数。
--例:查询3门以上课程是90分以上的学生的学号以及90分以上的课程数
select Sno,count(*)
from sc
where Grade>=90
Group By Sno
Having count(*)>=3
多表查询
连接查询
-
广义笛卡尔积(交叉连接)
SELECT Student.*,SC.* FROM Student,SC
-
等值连接(包含自然查询)
SELECT Student.Sno,sname,cno FROM Student,SC WHERE Student.Sno = SC.Sno; //连接条件
不同表中的同名属性必须加表名前缀。
-
自然查询:特殊的等值查询,把目标列中重复的属性列去掉。
-
非等值查询:连接运算符不是
=
号的连接 -
内连接
select ... from <表名> join <表名> on <连接条件> [where ...]
-
自连接
-
一个表与其自己进行连接
-
需要给表的两个副本起别名以示区别
-
必须使用别名前缀
-
例:查询每一门课的先修课的先修课
SELECT FIRST.Cno,SECOND.Cpno FROM Course AS FIRST,Course AS SECOND WHERE FIRST.Cpno = SECOND.Cno;
-
-
外连接
-
普通连接只输出满足连接要求的元组;外连接则以指定表为连接主体,将主题表中不满足连接条件的元组一并输出。
-
格式:
FROM <表名> [LEFT|RIGHT|FULL|OUTER] JOIN <表名> ON <连接条件>
Mysql不支持全外连接,可以用
Left join Union Right join
代替。 -
例: 查询每个学生及其选修课程的情况,包括没有选修课程的学生
SELECT Sname FROM Student,SC WHERE Student Right Join SC on Student.Sno = SC.Sno;
-
子查询
一个SELECT-FROM-WHERE
语句称为一个查询块,通常将一个查询块嵌套在另一个查询块的WHERE子句或HAVING短语的条件中。
子查询中不能使用ORDER BY子句。
插入FRMO子句,作为临时表使用:需要起一个别名
SELECT IS.SNO,SNAME,CNO
FROM SC,(SELECT SNO,SNAME
FROM STUDENT
WHERE SDEPT = 'IS') AS SIS
WHERE SC.SNO = SIS.SNO
上述AS SIS
就给临时表起了一个别名。
相关子查询
子查询的查询条件依赖于父查询。
- 首先取外层查询中的第一个元组,根据它与内层查询相关的属性值处理内层查询;
- 若WHERE子句返回值为真,则取此元组放入结果表
- 然后取外层表的下一个元组。重复该过程。
不相关子查询
子查询的查询条件不依赖于父查询。
由里向外逐层处理,即求解父查询之前先求解子查询,作为父查询的查找条件。
带IN
谓词的子查询
例:查询与刘晨在同一个系学习的学生(一个学生可能在多个系)
SELECT SNO,SNAME,SDEPT
FROM STUDENT S1
WHERE S1.SDEPT IN
(SELECT SDEPT
FROM STUDENT S2
WHERE S2.SNAME='刘晨')
是不相关子查询。S1,S2为定义的别名。
带比较运算符的子查询
当能确切地知道内层查询返回单值时,可以使用比较运算符。
例:查询与刘晨在同一个系学习的学生(一个学生只能在一个系)
SELECT SNO,SNAME,SDEPT
FROM STUDENT S1
WHERE S1.SDEPT =
(SELECT SDEPT
FROM STUDENT S2
WHERE S2.SNAME='刘晨')
用=
替换了IN
。
注意,子查询一定要在比较运算符之后。
WHERE(...)=SDEPT
的写法是错误的。
带ANY
或ALL
的子查询
ANY
:子查询中的任意一个值
ALL
:子查询中的所有值
与比较运算符配合使用。
如:
> ANY 大于子查询结果的某个值(有一个即可)
< ALL 小于子查询结果的所有值(必须全部满足)
!=(或<>) ANY 不等于子查询结果中的某个值
!=(或<>) ALL 不等于子查询结果中的任何值
例:查询其他系中比信息系任意一个(其中某一个)学生年龄小的学生姓名
SELECT SNAME
FROM STUDENT
WHERE SAGE < ANY (
SELECT SAGE
FROM STUDENT
WHERE SDEPT = 'IS'
)
AND SDEPT != 'IS'
实际上有的情况能用集函数就用集函数,效率更高。
select Sname
from student
where Sdept!="IS"
and age < (select MAX(age)
from student
where sdept="IS")
带EXISTS
/NOT EXISTS
的子查询
这种子查询不返回任何数据,只产生逻辑值true
orfalse
若内层查询结果非空则返回真;
内层查询结果为空则返回假。
所以以EXISTS
引出的子查询目标列通常用*
。
例:查询所有选修了1号课程的学生姓名
SELECT SNAME
FROM STUDENT
WHERE EXISTS
(SELECT *
FROM SC /*相关子查询*/
WHERE SNO = STUDENT.SNO
AND CNO = '1');
- 在STUDENT表中依次取每个元组的SNO值,用此值检查SC关系
- 若SC中存在这样的元组,其SNO值等于此STUDENT.SNO值, 并且其CNO= '1',则取此STUDENT.SNAME送入结果关系。
相关子查询的WHERE条件中会出现父查询FROM用到的表格;
但子查询中的FROM中往往没有该表格。

上例过程中,如果某学生没有选某科,则第二层子查询(从紫色Where not exists
开始)返回真(不存在这样一条记录,某学生选择了某科);第一层子查询(红色)返回假,该学生的Sname
不被选中。

这种双重否定的问题,最内层子查询的条件就是“返回正确”的条件。
EXISTS子查询也可以用于不相关子查询。
SELECT * FROM A WHERE EXISTS (SELECT * FROM B)
集合查询
标准SQL支持的集合操作种类:
- 并操作
union
一般商用数据库支持的:
- 并操作
union
- 交操作
intersect
- 差操作
except
例:查询计算机系的学生及年龄不大于19岁的学生
select *
from student
where sdept="CS"
union
select *
from student
where sage<=19;
DDL语言
定义数据库模式。数据库模式包括数据库中的关系的声明,以及视图、索引、触发器等对象。
DDL语言完成数据库对象的创建、删除和修改。
定义基本表
create table <表名>
(<列名><数据类型>[完整性约束条件],
<列名><数据类型>[完整性约束条件],
...,[表级完整性约束条件])
例:
create table Student
`(sno char(5) not null unique,
sname char(20) unique,
Sage int)
常用数据类型:
int/integer
,real/float
,char(n)
定长字符串,varchar(n)
变长字符串(n为字符串最大长度),date
,time
常用完整性约束:
- 主键约束:
primary key
- 唯一性约束:
unique
- 非空值约束:
not null
- 参照完整性约束:
references
删除基本表
drop table <表名>
修改基本表
alter table <表名>
add <新列名> <数据类型> [完整性约束]
drop <完整性约束名或列名>
modify<列名><数据类型>
如:删除列
ALTER TABLE Student
Drop Sage;
删除学生名字唯一的约束:
alter table Student
drop unique(name)
modify
:用于修改列的数据类型。
DML语言
数据更新语言。
Insert
-
插入单条元组:
insert into <表名> [<属性列名1>,<属性列名2>,...] values (常量1,常量2,...)
没有指定属性列时则插入一条完整的元组,且属性列属性顺序与表中相同
-
插入子查询结果
insert into <表名> 子查询; --例: insert into Deptage(sdept,Avgage) select sdep,AVG(Sage) from student Group By Sdept
select distinct teacher from (select teacher,c.c#,avg(grade) from s,sc where sc.c#=c.c# group by teacher,c.c#) as result (teacher, c#,avg_grade) as x where 80<=all(select avg_grade from result as y where y.teacher=x.teacher)
Update
-
修改某一个元组/很多个元组
update <表名> set <列名1>=<表达式1>,<列名2>=<表达式2>,... [where <条件>]
-
带子查询的:
UPDATE SC SET Grade=0 WHERE 'CS'= (SELECT Sdept FROM Student WHERE Student.Sno = SC.Sno);
没有where
表示要修改表中所有的元组。
Delete
-
删除某个元组:(查出来多个就删多个)
delete from student where sno = '90900'
-
删除所有学生的选课记录
delete from sc
-
带子查询的删除:
delete from sc where 'CS'=( select sdept from student where student.sno=sc.sno )
DCL语言
数据控制语言。可以实现:
- 授予或回收访问数据库的某种特权
- 控制数据库操纵事务发生的时间和效果
- 对数据库实行监视
视图
视图是一种虚表,是从一个或几个基本表(或视图)中导出的表。是在数据字典中存储的一条Select语句。
-
DBMS在执行
Create view
语句时,只是把视图的定义存入数据字典,并不执行其中的Select语句; -
在对视图查询时,按视图的定义从基本表中将数据查出
-
对于可更新的视图,可以对视图执行数据更新操作,数据库会根据视图定义去更新对应的基本表数据。
视图定义语句格式:
Create view
<视图名>[列名1,...]
AS <子查询>
[With Check Option]
定义时,组成视图的属性列名需要全部省略或全部指定。
必须指定的情况:某个目标列式集函数或列表达式;多表连接中选出了同名列作为字段。
例如:
Create view is_student
as
Select sno,sname,sage
From student
Where Sdept='IS'
可以基于视图建立新的视图。
With Check Option
:
在透过视图进行增删改操作时,不能破破坏视图定义中的谓词条件,即子查询中的条件表达式。
不可更新的视图:
- 聚合函数的使用:包含如
SUM()
,AVG()
,MIN()
,MAX()
,COUNT()
等聚合函数。 - 使用 DISTINCT 关键字:如果视图使用了
DISTINCT
关键字来去重显示数据,视图将不可更新,因为去重后的数据不再直接映射到唯一的底层数据行。 - 包含多表连接:如果视图是通过连接多个表来构造的,尤其是当连接涉及非主键到非主键的连接时,这样的视图通常不可更新。即使是基于主键的连接,更新操作也可能因为引起数据不一致而受限。
- 使用子查询:如果视图中的 SELECT 语句包含不能直接与单一表行对应的子查询,这种视图也不可更新。
- 使用 UNION 或 UNION ALL:视图中使用了
UNION
或UNION ALL
操作的,因为这些操作涉及到跨多个表的数据组合,不清楚更新应该影响哪个基表或如何影响。 - 包含非可更新的视图:如果视图是基于其他非可更新的视图构建的,那么这个视图也不可更新。
- 只读视图。
- 包含计算列或转换函数:如果视图的列包含计算或通过函数转换得来的结果(如
CONCAT
,DATE_FORMAT
),更新这样的视图也可能受限,因为这些计算或转换不直接反映原始数据。 - 分组操作:视图中包含
GROUP BY
子句时,通常不可更新,因为分组后的结果不再是单一数据行的直接表示。
视图的作用
- 简化用户操作
- 对基本表进行数据抽取和组合,形成不同的观察窗口,使不同用户以不同方式看待同一数据。
- 对重构数据库提供了一定程度的逻辑独立性
- 能对机密数据提供安全保护
数据库编程
数据库程序开发
对数据的开发处理主要由数据库应用程序来完成,它有两种形式:
- 数据库内部应用程序
- 数据库外部应用程序
数据库内部程序常见形式:
- 存储过程
- 函数
- 触发器
下面以存储过程为例。
-
定义:由过程化SQL语句书写的过程,经编译和优化后存储在数据库服务器中,使用时只需要调用即可。
通常将多次重复执行的代码段编写成一个过程,保存在数据库中
-
优点:
是SQL和模块化编程的结合,能够完成复杂业务功能。
创建时进行预编译,可以提高执行效率
位于数据库服务器上,调用时无需通过网络传输大量数据
可以作为一种安全机制。
-
创建:
create procedure procedure_name( [in|out|inout]param_name type[,...] ) [begin] sql_statement #一个过程化sql块 [end]
-
删除与调用
drop procedure procedure_name call procedure (parama_name type[,...])
-
游标编程
cursor
SQL语言无法实现遍历关系表、对每行数据进行单独处理。游标则可以对查询语句返回的行结果集中的每一行进行操作。包括:
- 定位到结果集中的指定行
- 从结果集的当前位置检索一行或多行
- 可以对结果集中当前位置的行进行数据修改
- 显示其他用户对结果集中的数据库数据进行的数据修改
过程:
- declare声明游标变量
- open打开游标变量
- fetch从结果集中抽取记录
- close关闭结果集
数据库系统开发
ORM 对象–关系映射
- O–R映射:用户开发和维护一个中间件层,负责将对象数据映射到关系数据库的表中
- 系统中其他模块可以通过OR映射层以操作对象的方法操作关系表中的数据
- 实现方案:active record 和data mapper。
Active Record
将对象和数据库表看做一一对应的关系,一个对象对应一个数据库表中的一行数据,对象和行数据之间的映射关系由ORM框架自动维护——通过对象的属性来操作数据表。
优点:简单,好理解
缺点:耦合度高,性能较差
Data Mapper
将对象和数据库表看作两个独立的概念,需要手动定义对象属性和数据库表字段之间的映射关系。对象的读写操作不直接与数据库交互,而是通过数据访问对象来实现。
优点:灵活性高,性能好
缺点:复杂,部署困难
ORM的优点
- 提升开发效率
- 数据库平台透明,数据库结构自动维护
- 代码可读性高
ORM的缺点
- 需要一定的学习成本
- 性能问题
- 不适用于复杂场景
开发模式
- MVC:视图、控制器、模型。耦合度低,重用性高。
- MVP:模型与视图完全分离,可以修改视图而不影响模型
- MVVM:与MVP很相似,最大的不同在于View和ViewModel之间主要是通过数据绑定的方案来实现交互的。
Docker
一种轻量级的虚拟化技术,通过隔离应用程序和其依赖的环境来实现应用程序的快速交付和部署。
与传统的虚拟化方式相比,Docker容器使用的底层资源更少、启动速度更快,因此可以更高效地利用计算机资源。
- 环境隔离
- 可靠性
- 方便测试
存储与索引
存储
存储介质
数据存储原则:在内存中存放常用数据;在磁盘中存放业务数据;在三级存储器中存放归档数据。
磁盘结构:盘面、磁道、扇区
磁盘的最小存取单元:页面
数据的存储结构
逻辑存储结构:
块——区——段——表——数据库
物理页面结构:页面头;记录地址;记录数据。
文件组织结构:数据文件中页面之间的组织方式;
常见文件结构类型:
- 堆组织表:记录顺序没有限制,数据排列顺序不可预测。
- 索引组织表
- 聚簇表
索引 Index
- 索引是主表上的一种辅助数据结构。
- 对数据库表中一个或多个列的值进行排序,用于提高主表的查询速度。
- 为基本表附加索引后,基本表的索引字段数据更新会引起索引的重构,造成数据库更新性能下降。因此索引的重构代价是考察索引性能的重要指标。
B+树索引
-
将索引键组织成一棵平衡树;
-
数据存储在叶节点;最底层的叶节点包含每个索引键和指向被索引行的指针
-
叶节点之间可以平行查询;
-
每一个叶节点都和磁盘页面大小一致;
-
查询的时间复杂度:O(logmn),m为B+树的分叉数。
相较于B树索引,B+树:
- 范围查询的效率更高
- 缓存命中率更高
- 更新维护代价更小
散列索引(hash)
B+树索引需要3次左右磁盘IO才能查到数据记录;
散列索引只需要一次磁盘IO就可以查到数据记录。
散列索引溢出块:哈希冲突的解决方法
散列索引的特点:
- 散列索引是CPU密集型的,B+树索引是IO密集型的
- 散列索引在等值查找时速度很快;
- 散列索引无法用于范围查找
- 不适合在重复值很多的列上建立散列索引
- 重构代价很大,不适合在更新频繁的表中建立
聚簇索引
大多数关系表以堆组织表的形式存放;但建立聚簇索引后,数据在屋里文件中的存放位置不再是无序的,而是根据索引中的键值逻辑决定了表中相应行的物理顺序,即形成索引组织表。
特点:
- 一张表只能有一个聚簇索引
- 聚簇索引列上的查询速度比B+树快
- 范围查询快
- DML频繁的表中不要建立聚簇索引
- MySQL在表的主键上建立聚簇索引
联合索引
加速这种查询:
Select *from tb where a>1 and b=1
在(a,b)字段上建立联合索引。
最左前缀原则:
- 只有在查询条件中使用了联合索引的最左前缀(最左边字段)时,该联合索引才生效;
- 上例中若执行下述查询语句则联合索引不生效 :`` Select * from tb where b=1`
另外,where
表达式左边不能包含计算式。
查询优化
一般准则:
- 选择运算应该尽可能先做,以减小中间关系
- 在执行连接操作前对关系适当进行预处理
- 投影运算和选择运算同时做,避免重复扫描关系
完整性约束
数据库的完整性:
- 数据库的正确性和相容性
- 防止不合语义的数据进入数据库
- 完整性:是否真实地反映现实世界。
完整性控制机制:
- 完整性约束条件定义机制
- 完整性检查机制
- 违约反应
完整性约束条件
完整性约束条件:
- 对象:
- 列:对属性的取值类型、范围、精度等的约束条件
- 元组:对元组中各个属性列之间的联系的约束
- 关系:对若干元组间、关系集合上以及关系之间的联系的约束
- 状态:
- 静态:反应数据库状态合理性的约束;
- 动态:反应数据库状态变迁的约束,涉及新值和旧值。
- 分类:以上对象3种×状态2种,共六类完整性约束条件。
静态列级约束
对列的取值域的说明,如取值类型、取值范围、是否为空值等。
静态元组约束
规定元组的各个列之间的约束关系。
例如:有订货关系(ID,商品,订货量,发货量)
要求每条记录中:发货量<=订货量
(同一行不同列)
用Check约束实现。
静态关系约束
关系的各个元组之间或若干关系之间存在的各种联系或约束。
例如:工资表(职工ID,工资,是否为经理)
要求职工平均工资*2<部门经理工资<职工平均工资*5
(不同行、不同表)
需要用触发器实现。
动态列级约束
修改列定义或列值时应该满足的约束条件。
- 修改列定义时的约束(数据库自动实现)
例:将原来允许空值的列改为不允许空值时: 该列目前已存在空值,则拒绝这种修改
- 修改列值时的约束 修改列值时新旧值之间要满足的约束条件(使用触发器实现)
例:年龄只能增大
动态元组约束
修改元组时,各个字段之间要满足的约束条件
用触发器实现
动态关系约束
对关系变化前后状态的限制条件。
详见事务处理部分。
完整性控制
指按完整性约束的定义、检查和违约反应规则。
用五元组表示:
D:约束作用的数据对象
O:触发完整性检查的操作
A:数据对象必须满足的断言或语义约束
C:选择A作用的数据对象值的谓词
P:违反规则时触发的过程
违约反应
- 拒绝执行
- 接受,但同时执行一些附加的操作。
操作:
- 级联删除or修改
- 受限删除or插入or修改
- 置空值删除or修改
- 递归插入
用户自定义约束的实现
Check约束
表达式可包含列名、比较运算符(>、<、=等)
逻辑运算符(and、or等)、条件谓词(in、like等)
可使用pattern(如_ 、%通配符,[]选择符等)
常用于实现静态列级约束和静态元组约束。
触发器Trigger
触发器是用于实现复杂逻辑的用户自定义约束的工具,是一种特殊的存储过程:
- 与表紧密相连,不能脱离宿主存在
- 由数据库自动调用执行,用户不能调用
- 没有参数和返回值
- 是一种Event-Condition-Action规则的实现
定义语句包括:
-
事件&时机
-
执行粒度:
-
语句级触发器:每条用户语句触发一次,默认;
-
行级触发器:FOR EACH ROW
对于表中每条受影响记录,触发一次触发器。
-
-
Referencing引用:
可以通过引用来处理新值、旧值。MySQL中可以直接使用New、Old来引用。
- 名为Inserted的表,包含新插入的行
- 名为Deleted的表,包含删除的行
-
条件 WHEN…(MySQL不支持)
-
动作
通常用于进行关联数据更新,不能返回查询结果
若需多于一条语句,则可用程序块实现:Begin…End
数据库安全
数据库安全指的是:保护数据库,防止因用户非法使用数据库造成数据泄露、更改或破坏等恶意人为破坏问题。
安全认证
确认试图登录数据库的用户是否被授权访问数据库的过程。
认证方式:
- 数据库认证:最常用的是密码认证
- 外部认证
- 强身份认证:提高数据库性能
- 代理认证:有效解决网络上节点伪造身份
访问控制
按照用户的身份和权限,控制用户对数据库中的数据访问。
- 权限分类:

-
权限授予:Grant,权限收回:Revoke
能授予、收回权限的人:
- 数据对象的创建者
- DBA(数据库管理者)
- 拥有传播权限的用户
-
角色分类:服务器角色,数据库角色,Pubulic角色
-
角色可以从属于别的角色,获得别的角色定义的权限
数据保护
数据审计
事务管理
并发控制
当多个用户同时存取、修改DB中的数据时,可能发生干扰,破坏数据库的完整性。
数据的一致性:在任何时刻用户面对的数据库都是符合现实世界的语义逻辑的。
数据库的并发控制是以事务为基本单位进行的,属于动态关系约束。
事务
事务是并发控制的基本单位,也是遇到各类数据库错误后进行数据恢复的处理单位。
事务由有限的数据库操作序列组成。
为了保护数据的完整性,一般要求事务具有ACID四个特征:
- 原子性(Atomicity)
- 隔离性(Isolation):并发执行的各个事务之间不能互相干扰。
- 一致性(Consistency):事务执行前是一致的,执行过程中可能暂时出现不一致,事务执行完后,数据库仍会处于一致性状态。
- 持久性(Durability):一个事物一旦提交后,它对数据库的影响必须是永久的。系统发生失效不能改变事务的持久性。
事务的状态:

数据库的恢复机制:影子数据库技术。
保证了原子性和持久性的实现,但无法保证隔离性和一致性。
事务的并发执行
并发操作带来的数据不一致性:
- 丢失修改:两个事务修改同一个数据(写,写)
- 不可重复读:事务1读取数据后,事务2执行更新,使事务1无法再现前一次读取结果(读,写,读)
- 读“脏”数据:事务1修改某一数据,并将其写回磁盘。事务2读取同一数据后,事务1由于某种原因被撤销(ROLLBACK),此时事务2读取到的就是不正确的“脏”数据。(写,读,撤回)
调度
串行化调度:先T1,再T2,T3……显然串行调度能保证数据库的一致性。
几个事务的并行执行是正确的,当且仅当其结果与按某一次序串行地执行它们时的结果相同。这种并行调度策略称为可串行化的调度。
并行调度正确 = 可串行化。
冲突可串行化
还有视图可串行化,但这里不讨论。
-
冲突:对同一对象分别进行读写/写写。
-
如果两个指令不冲突,则它们的执行顺序不会影响最终的执行结果。
-
冲突可串行化:如果一个调度S可以通过一系列的非冲突指令顺序调换而被转化为另一个调度S’,则我们说S和S’是冲突等价的;
如果S’是一个串行化调度,则S是冲突可串行化的。
测试冲突可串行化的方法:前驱图。

当且仅当前驱图是无环的时候,对应的调度是冲突可串行的。
可恢复的调度
如果事务T2读取了一个事务T1之前写入的数据,则T1的提交操作应该在T2的提交操作之前发生。可以避免由于数据回滚导致的不一致问题。
无级联调度
-
级联回滚:如果一个调度(T10)失败了,会引起其他调度(T11,T12)的一连串回滚,这会导致事务运行不畅。
-
无级联调度:每一对事务,若T2读取了一个事务T1之前写入的数据,则T1的提交操作应该在T2的读取操作之前。
满足无级联调度一定满足可恢复调度。
并发控制
保证并发调度的正确性的方法:
封锁方法,时标方法,乐观方法,多版本并发控制。这里只介绍封锁方法。
基本的封锁类型:
-
排它锁(exclusive,X锁)
又称写锁。 若事务T对数据对象A加上X锁,则只允许T读取和修改A,其它任何事 务都不能再对A加任何类型的锁,直到T释放A上的锁。
-
共享锁(share,S锁)
又称读锁。若事务T对数据对象A加上S锁,则其它事务只能再对A加S锁,而不能加X锁,直到T释放A上的S锁。
封锁协议
封锁协议设定了封锁实际的规则,包括何时申请X锁或S锁、持续时间以及何时释放。
不同的封锁协议,可以在不同的程度上为并发操作的正确调度提供一 定的保证。
包括三级封锁协议、两阶段锁协议。
三级封锁协议
-
一级封锁协议
事务T在修改数据R之前必须对其加X锁,直到事务结束才释放。
有S锁必不是一级封锁协议。
一级封锁协议可以防止丢失修改;
读数据不需要加锁,所以不能保证可重复读和不读脏数据。
-
二级封锁协议
在一级封锁协议的基础上,要求事务T在读取数据R前必须加S锁,读完后即可释放S锁。
二级封锁协议可以防止丢失修改和读“脏”数据。
在二级封锁协议中,由于读完数据后即可释放S锁,所以它不能保证可重复读。
-
三级封锁协议
在一级封锁协议的基础上,要求事务T在读取数据R之前必须先对其加S锁,直到事务结束才释放。
三级封锁协议可以防止丢失修改、读脏数据和不可重复读。
注意事务结束指的是commit提交时,而不是所有操作结束后。
三级封锁协议与事务隔离级别:
- 读未提交:相当于1级封锁协议
- 读已提交:相当于二级封锁协议
- 可重复读:低于三级封锁协议
- 串行化:相当于三级封锁协议

两阶段锁协议
-
在对任何数据进行读、写操作之前,事务首先要获得对该数据的封锁
-
在释放一个封锁之后,事务不再获得其他任何封锁。
-
事务分为两个阶段:获得锁的扩展阶段和释放锁的收缩阶段。
但是两段锁协议不能解决级联回滚问题。
解决方案:严格的两段锁协议:
- 在两阶段锁协议基础上,增加规则:事务获得的锁只有在事务结束时才释放。
三级封锁协议与严格的两阶段锁协议一致。
死锁
预防死锁的方法:
- 一次封锁法:要求每个事物必须一次将所有使用的数据全部加锁,否则不能继续执行。
- 一次封锁法存在的问题:将以后要用到的数据全部加锁,势必扩大了封锁的范围,降低了系统的并发度
死锁的诊断与解除:
-
允许死锁发生;
-
解除死锁:由DBMS的并发控制子系统定期检测系统中是否存在死锁
-
等待图法检测死锁
备份与恢复
恢复技术是系统安全性的重要保证,可以保证事务的原子性和持久性。
事务原语:
- INPUT(X):把数据项X读入内存缓冲区
- READ(X,t):把数据项X拷贝到事务的本地变量t中
- WRITE(X,t):把事务本地变量拷贝回数据项X
- OUTPUT(X):将数据项X写到磁盘里记录下来
缓冲区处理策略:
- Force:内存中的数据最晚在commit时写入磁盘
- No Force:内存中的数据可以一直保留,在commit之后一段时间再写入磁盘(系统崩溃时数据可能还没写入磁盘)
- No Steal :不允许在commit之前把内存中的数据写入磁盘
- Steal:允许事务在commit之前把内存中的数据写入磁盘(系统崩溃时可能有未提交的数据被持久化了)
当前数据库常用No Force + Steal策略,以提升数据读写性能。
故障的种类
事务故障
-
定义:某个事务在运行过程中由于种种原因未运行至正常终止点就夭折了。
-
原因:输入数据有误;运算溢出;违反了某些完整性约束;并行事务发生死锁……
事务故障只会影响事务本身。
-
恢复:
- 发生事务时,夭折的事务可能已把对数据库的部分修改写回磁盘。
- 撤销事务:对未提交事务进行强制回滚,清除该事物对数据库的所有修改,消除未提交事务的影响。
系统故障
-
定义:整个系统的正常运行突然被破坏,所有正在运行的事务都非正常终止;内存中数据库缓冲区的信息全部丢失,外部存储设备上的数据未受影响。
-
原因:操作系统或DBSM代码错误;操作员操作失误;硬件错误
-
恢复:
- 清除尚未完成的事务对数据库的所有修改。
- 将缓冲区中已经完成事务提交的结果写入数据库。
- 实现上需要日志文件的帮助。
介质故障
-
定义:硬件故障使存储在外存中的数据部分或全部丢失。
-
原因:磁盘损坏,磁头碰撞等。
会影响到内存中的数据和磁盘上的数据。
-
恢复:
- 装入数据库发生介质故障前某个时刻的数据副本
- 重做自此时始所有成功事务,将这些事务已提交的结果重新记入数据库。
- 实现上,需要数据转储副本(备份数据)和日志文件。
恢复技术
恢复操作的基本原理:冗余。利用存储在系统其他地方的冗余数据来重建数据库中已被破坏或不正确的那部分数据。
数据转储:指DBA将整个数据库复制到磁带或另一个磁盘上保存起来的过程。
数据转储方法:静态转储与动态转储;全量转储与增量转储
静态转储
在系统无运行事务时进行转储。
- 转储开始时数据库处于一致性状态
- 转储期间不允许任何存取、修改活动
- 优点:实现简单
- 缺点:降低了数据库的可用性
动态转储
转储操作与用户事务并发执行,转储期间允许对数据库进行存取或修改。
优点:不用等待正在运行的用户事务结束;不会影响新事物的运行。
缺点:不能保证副本中的数据正确有效。
恢复策略
进行故障恢复时,对已提交事务进行重做;对未提交事务进行撤销(回滚)。
例题:
基于Undo日志的恢复策略
Undo日志记录的规则:
-
如果事务T更新了数据项X,则日志记录<T,X,v>必须在X被写入磁盘之前写入磁盘。
更新操作:日志先写,磁盘后写
-
如果事务T提交,则日志记录<COMMIT T>只有在T所做的所有修改都被写入数据文件后才能写入日志文件。
Commit操作:数据文件先写,日志后写。
性能较差;通常在事务故障时根据Undo日志进行回滚操作,保证事务的原子性。
基于Redo日志的恢复策略
规则:
如果事务T更新了数据项X,则日志记录<T,X,v>和<COMMIT T>必须在X被写入数据文件之前写入日志文件。
Redo日志先写,数据文件后写。
提升了数据库的性能,但不允许Steal模式。
通常在系统故障时根据Redo日志进行已提交事务的重做,保证事务的持久性。
基于Undo/Redo日志的恢复策略
规则:
如果事务T 更新了数据项X,则日志记录 必须在X 被 写入数据文件之前写入日志文件;Commit则之前、之后皆可。
No Force+Steal模式下需要该日志。
基于检查点的恢复策略
在日志文件中添加检查点记录,以最新的检查点作为下次恢复工作的起点。
检查点记录内容:建立检查点时刻所有正在执行的事务清单;这些事务最近一个日志记录的地址。
<START CKPT (T2,T3)>里面的T2 T3就是正在执行的事务清单。
重新开始文件的内容:各个检查点在日志文件中的地址。
恢复策略:
- 检查点之前提交的事务不需要恢复
- 对于检查点之后才提交的事务,其恢复过程:
- 从重新开始文件中找到最后一个检查点记录在日志文件中的地址
- 由该地址在日志文件中找到最后一个检查点记录
- 由该记录点记录得到检查点建立时刻所有正在执行的事务
- 从检查点开始正向扫描日志文件,直到日志文件结束,对读到的事务建立已提交和未提交队列。
- 对已提交事务进行Redo操作,对未提交事务进行Undo操作。
关系数据理论
一个好的关系模式应该具备以下四个条件:
- 尽可能少的数据冗余
- 没有插入异常
- 没有删除异常
- 没有更新异常
如何按照一定的规范设计关系模式,将结构复杂的关系分解为结构简单的关系,这就是关系的规范化。
关系数据库的规范化理论主要包括三个方面的内容:
- 函数依赖
- 范式
- 模式分解
其中函数依赖起着核心的作用,是模式分解和模式设计的基础,范式是模式分解的标准。
一个好的关系模式应该:
- 尽可能少的数据冗余
- 没有插入异常
- 没有删除异常
- 没有更新异常
函数依赖
关系模式中各属性之间相互依赖、相互制约的联系称为数据依赖。
数据依赖一般分为函数依赖、多值依赖和连接依赖。
其中,函数依赖是最重要的数据依赖。
定义:当某个值X确定时,另外一个值Y也被确定,则称Y函数依赖于X。记作X→Y。
若Y可以被(X,Z)所确定,则可以表示为(X,Z)→Y。
作用:函数依赖可以保证关系分解的无损连接性。
关系分解的无损连接性:
![]()
- 完全函数依赖
- 部分函数依赖
- 传递函数依赖


范式
关系数据库的规范化过程中为不同程度的规范化要求设立的标准称为范式。
候选键:能唯一标识一个元组的。
主键:选定的一个候选键。
主属性:在任意一个候选键中出现过的属性。
非主属性:主属性之外的属性。
外键:另一个关系模式的候选键。
1NF
如果关系模式R,其所有的属性都是简单属性(即每个属性域都是不可再分的),则R属于第一范式。
注意不是让关系键为单属性。
第一范式排除了多值属性、组合属性。
数据冗余、三个异常都没有解决。
2NF
定义:在1NF的基础上,如果每个非主属性都完全函数依赖于R的每个关系键,则R属于2NF。
如果R的关系键(主键)为单属性,或R的全体属性均为主属性,则R属于2NF。
规范化的实现:把1NF关系模式进行投影分解。
找出部分函数依赖,并拆分。
2NF中,四个问题仍然没有解决,因为存在着非主属性对主键的传递依赖。
3NF
定义:在2NF的基础上,使每个非主属性都不传递依赖于R的每个关系键,则R属于3NF。
3NF中,数据冗余降低,基本不存在三种异常。
但是3NF中可能存在主属性对键的部分函数依赖。
BCNF
如果关系模式R属于1NF,且所有的函数依赖X→Y中,X都包含了R的一个候选键,则称R属于BCNF。
满足BCNF的关系将消除任何属性对键的部分函数依赖和传递函数依赖。满足BCNF一定满足3NF。
彻底消除了三种异常,数据冗余极小。
非规范化设计
为了提升运行效率。
- 增加冗余列:多个表中有相同的列。查询时避免连接操作
- 增加派生列:增加的列来自其他表中的数据。减少连接操作,避免使用集函数。
- 重新组表:把两个表组成一个表来减少连接。
- 表分割:水平分割、垂直分割。
模式分解
模式分解要解决的:
设
简单来说,就是如何将一系列复杂的、具有函数依赖的关系,从一个表转化为两个或多个表,同时保证3NF、无损连接、消除数据异常。
模式分解的定义:

数据依赖的公理系统
-
逻辑蕴含:对于满足一组函数依赖F的关系模式
,其中任何一个关系r,若函数依赖X—>Y都成立,则称F逻辑蕴含X—>Y。关系模式
中,U是组成该关系的属性名集合;F是属性间数据的依赖关系的集合。
Armstrong公理系统:
-
推理规则:对于关系模式
-
自反律:
,则X →Y为 F所蕴含。由自反律得到的函数依赖都是平凡的函数依赖。
-
增广律:若X—>Y为F所蕴含,且
,则XZ—>YZ为F所蕴含 -
传递律:若X—>Y及Y—>Z为F所蕴含,则X—>Z为F所蕴含。
所蕴含:翻译成人话就是F中有这样的依赖关系。
由上述三条推理规则又可以得到:
- 合并规则:由X→Y,X→Z,有X→YZ。
- 伪传递规则:X→Y,WY→Z,有XW→Z。
- 分解规则:由X→Y及Z⊆Y,有X→Z。
由合并规则和分解规则可得引理:
成立的充要条件是 成立 -
-
函数依赖闭包:在关系模式
中为F所蕴含的函数依赖的全体叫F的闭包,记作F+。从F由上述规则拓展出来的函数依赖的全体。
-
引理:设F为属性集U上一组函数,X→Y能由F根据Armstrong公里导出的充要条件是
-
用途:将判定X→Y是否能由F根据公理导出的问题,转化为求出
,判定Y是否为其子集的问题。
求


公理系统的有效性:从F出发根据Armstrong公理推导出来的每一个函数依赖一定在F+中。公理系统是正确的。
公理系统的完备性:F+中的每一个函数依赖,必定可以由F出发根据Armstrong公理推导出来。公理系统是完备的。
覆盖和等价:如果G+=F+,就说函数依赖集F覆盖G,或F与G等价。
极小函数依赖集
又称最小依赖集或最小覆盖。
满足以下条件的F被称为一个极小函数依赖集:
- F中任一函数依赖的右部仅含有一个属性;
- F中不存在这样的函数依赖
,使得F与 等价 - F中不存在样的函数依赖
,X有真子集Z使得 与F等价。
函数依赖的右部只有一个属性;左部多属性之间没有完全依赖关系;不存在传递可以得出的函数依赖;不存在部分依赖。
构造最小依赖集Fm:


Fm不一定是唯一的,也不一定要求所包含的依赖的数量最少。
模式的分解
模式分解的定义:

模式分解是否正确的判定依据:
-
分解具有无损连接性
即R与ρ在数据内容方面是否等价
-
分解保持函数依赖
即R与ρ在函数依赖方面是否等价
分解的无损连接性
上述定义的分解ρ中,若R与R1,R2,…,Rnd自然连接的结果相等,则称这个分解ρ具有无损连接性。
-
具有无损连接性的分解能保证不丢失信息
注意:丢失信息不止是信息缺失,还可能出现原来没有的元组。
-
无损连接性不一定能解决插入异常、删除异常、修改复杂、数据冗余等问题。
-
分解具有无损连接性和分解保持函数依赖是两个互相独立的标准。
无损连接性分解的判定方法:
-
列表法:见PPT例题。
列表:分解后在关系中的键为a,其他为b(每一列),标记下标。
根据依赖修改表格:使依赖左端相同的右端也相同;优先把b换成a。
最后如果有一列全为a,则是无损连接;否则为有损连接。
-
定理法
(适合于关系模式R分解为两个关系模式R1、R2时)
分解的函数依赖保持性
- 具有函数依赖保持性的分解,能减轻或解决各种异常情况。
判定方法:


对每一个F中的函数依赖的左段求在G中的闭包,观察闭包中是否存在右段:均存在则保持了函数依赖,反之没有。
关于G是什么:

正确分解到BCNF
正确分解到3NF
-
首先求得F的最小依赖集F’;
-
然后对F’中所有函数依赖按左边属性分组,每组中加入对应的右边属性,再加上候选键所组成的一个关系,就获得了保持函数依赖的3NF分解结果ρ
-
设X是R的候选键。如果ρ中某关系包含了X或被X包含,则进行去重。
总之就是一定要出现一整个候选键在某一个关系模式中。
例:

数据库设计
概述
数据库的设计包括静态的数据库结构设计和动态的数据库行为设计。
数据库设计方法主要有直观设计法和规范设计法。
新奥尔良法:将数据库设计分为需求设计、概念设计、逻辑设计和物理设计四个部分。
数据库设计的过程:
-
需求分析
了解与分析用户的需求,是最困难、最耗时的一步
-
概念结构设计
通过对用户需求进行抽象,形成一个独立于DBMS的概念模型。是整个数据库设计的关键
-
逻辑结构设计
将概念结构转化为某个DBMS所支持的数据模型
-
数据库物理设计阶段
为逻辑数据模型选取一个最适合应用环境的物理结构。
-
数据库实施
-
数据库运维
需求分析
重点:信息要求、处理要求、安全性与完整性要求
数据流图


- 分解处理功能和数据
- 将分析结果再次提交给用户。

数据字典
数据字典中的条目有:
- 数据项
- 数据结构
- 数据流
- 数据存储
- 处理过程
数据项是数据的最小组成单位。
概念结构设计
将需求分析得到的用户需求抽象为信息结构(即概念模型)的过程,就是概念结构设计。
概念机构设计比逻辑模型更独立于机器、更抽象,从而更稳定。
概念结构设计内容:
- 选择局部应用
- 逐一设计分E–R图
- 集成局部视图,得到全局概念结构
冲突的种类:
- 属性冲突(属性值类型、取值范围、单位等不统一)。
- 命名冲突
- 结构冲突
- 同一对象在某的地方被当做实体,在有的地方被当做属性。
- 同一实体在不同局部视图中,包含的属性不完全相同,或属性的排列次序不相同。(解决:取并集并统一排序)
- 实体之间的联系在不同局部视图中呈现不同类型。(多对多、一对多)
合并ER图:
-
简单合并,得到初步ER图
-
修改与重构:消除冗余,得到基本ER图
消除冗余的分析方法:以数据字典和数据流图为依据;
规范化理论:函数依赖的概念。
-
数据模型的优化:逐一分析关系模式,考察是否存在问题,属于第几范式。
-
分析是否需要用到非规范化设计手段。
逻辑结构设计
任务:将概念模型进一步转化为对应的数据模型。
内容:
- ER图向关系模型的转换
- 数据模型的优化
- 设计用户子模式
NoSQL和云数据库
分布式数据库
分布式数据库的起源:BigTable,用于解决Google的大规模网页搜索问题
HBase:是BigTable的开源实现,是一个高可靠、高性能、面向列、可伸缩的分布式数据库,主要用来存储非结构化和半结构化的松散数据。
HBase与RDB的对比:

HBase的实现包括三个主要的功能组件:
- 库函数
- Master主服务器:只有一个,负责管理和维护HBase表的分区信息,维护Region服务器列表。
- Region服务器:通常有多个,每个Region服务器存储10~1000个Region。负责存储和维护分配给自己的Region,处理来自客户端的读写请求
NoSQL简介
NoSQL特点:
- 灵活的可扩展性
- 灵活的数据模型
- 与云计算紧密融合
关系数据库已无法满足Web2.0的需求,主要表现在:
- 无法满足海量数据的管理需求
- 无法满足数据高并发的需求
- 无法满足高可扩展性和高可用性的需求
NoSQL技术特点
NoSQL的六大类型:
- 键值数据库
- 列族数据库
- 文档数据库
- 图形数据库
- 搜索数据库
- 时序数据库
三大基石:
-
CAP理论:
- 一致性
- 可用性:快速获得数据,可以在确定时间内返回操作结果)
- 分区容忍性:当出现网络分区(即系统中一部分节点无法和其他节点通信)时,分离的系统也能够正常运行;也就是说,系统中任意信息的丢失或失败不会影响系统的继续运作。
CAP理论说明,一个分布式系统不可能同时满足一致性、可用性和分区容忍性这三个需求,最多只能同时满足两个。
-
BASE理论:
- 基本可用:一部分不可用时,其他部分依然可用
- 软状态/柔性事务:状态可以有一段时间不同步,具有一定的滞后性
- 最终一致性:允许后续访问操作可以暂时读不到更新后的数据,但经过一段时间后,必须最终读到更新后的数据。最长常见的实现最终一致性的系统是DNS(域名系统)
NewSQL数据库
是各类新的可扩展、高性能数据库的简称。
不仅有NoSQL的海量数据存储管理能力,还保持了传统DB支持ACID和SQL等特性。
不同的SQL都有两个显著的共同特征:
- 都支持关系数据模型
- 都使用SQL作为其主要接口
云数据库概述
云数据库部署和虚拟化在云计算环境中的数据库,是在云计算大背景下发展起来的一种新兴的共享基础架构的方法。
具有高可拓展性、高可用性、采用多租形式和支持资源有效分发等特点。
云数据库不是一种全新的数据库技术,而只是以服务的方式提供数据库功能。
云数据库没有专属于自己的数据模型。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
· 上周热点回顾(2.17-2.23)