数据库基础知识
# 概述
数据库管理系统DBMS
数据定义功能DDL
数据组织,存储和管理
数据操纵功能DML
数据库的事务运行和运行管理
数据库的建立和维护功能
数据库数据的三个基本特点
永久存储
有组织
可共享
数据库系统的特点
数据结构化:与文件系统的本质区别
数据的共享性高,冗余度低而且易扩充
数据独立性高
数据由数据库管理系统统一管理和控制
与文件系统的另一个重要区别:数据库是支持事务的。
两类数据模型
概念模型:实体-联系方法
逻辑模型和物理模型:层次模型,网状模型,关系模型,面向对象数据模型,对象关系数据模型,半结构化数据模型
数据模型的组成要素
数据结构
数据操作
数据的完整性约束条件
关系模型的优缺点
关系模型是建立在严格的数学概念的基础上的
关系模型的概念单一,无论是实体还是实体间的联系都使用关系来描述。
关系模型的存取路径对用户透明,从而具有较高的数据独立性,更好的安全保密性。
缺点是查询效率不如格式化数据模型。
两层映像(保住了数据有较高的逻辑独立性和物理独立性)
外模式/模式映像:
模式/内模型映像:
关系语言的分类
关系代数语言:ISBL
关系演算语言:ALPHA,QUEL,QBE
结构化查询语言(介于关系代数和关系演算之间的语言):SQL
SQL语言:是一种高度非过程化的语言,用户不必请求数据库管理员为其建立特殊的存储路径,存储路径的选择由关系数据库管理系统的优化机制来完成。
SQL的特点
综合统一:集数据定义语言,数据操纵语言,数据控制语言的功能与一体。
高度非过程化:只要提出做什么而不需指明怎么做,因此无需了解存取路径。
面向集合的操作方式
以同一种语法结构提供多种使用方式
语言简明,易学易用
视图
行列子集视图:若一个视图是从单个基本表中导出的,并且只去掉了基本表的某些行或者某些列,但是保留了主码,则称这类视图为行列子集视图。
分组视图:用带有聚集函数和GROUP BY子句的查询来定义视图,这种视图叫做分组视图。(S_G视图)
**视图消解:**从数据字典中取出视图的定义,把定义中的子查询和用户的查询结合起来,转换成等价的对基本表的查询,然后再执行修正了的查询。这种转换过程叫做视图消解。
更新视图
一般行列子集视图可更新
S_G视图无法更新
若视图由两个以上基本表导出,则视图不允许更新
若视图的字段来自字段表达式或者常数,不允许INSERT,UPDATE,但是允许DELETE。
若视图中的字段来自聚集函数,视图不允许更新
视图中含有GROUP BY子句,视图不允许更新
视图中含有DISTINCT短语,视图不允许更新
视图定义中函数嵌套查询,并且内层查询的FROM子句中涉及的表也是导出该视图的基本表,则此视图不允许更新。
视图的作用
视图可以简化用户的操作
视图可以使用户以多种角度看待同一种数据
视图对重构数据库提供了一定程度上的逻辑独立性
视图对机密数据提供安全保护
适当使用视图可以更加清晰地表达查询
# 数据库安全性
自主存取控制
- 用户对于不同的数据库对象有不同的存取权限,不同的用户对于同一个对象也有不同的权限,而且用户可以将其拥有的存取权限转授给其他用户。
强制存取控制
每一个数据库对象被标记有一定的密级,每一个用户也被授予某一个级别的许可证。对于任意一个对象,只有具有合法许可证的用户才可以存取。
仅当主体的许可证级别大于或者等于客体的密级时,该主体才能读取相应的客体。
仅当主体的许可证级别小于等于客体的密级时,该主体才能写相应的客体。
# 数据库完整性
数据库的完整性和安全性
完整性:防止数据库中存在不符合语义的数据,也就是防止数据库中存在不正确的数据。
安全性:保护数据库以防止不合法使用所造成的数据泄露,更改或者破坏。
# 规范化
关系模式存在的问题
数据冗余
更新异常
插入异常
删除异常
数据依赖:一个关系内部属性与属性之间的一种依赖关系
函数依赖:属性x的值确定后,属性y的值也确定了。
多值依赖:对于任意关系,若存在两元祖记为A,B。若它们某一个属性X的值相等,那么交换它们另外的属性Y的值后,得到新的元祖在原来的表中可以找到与之匹配的元祖。
范式:关系数据库中的关系需要满足一定的要求,而对于不同程度的要求则为不同范式。
第一范式(1NF):数据库表中的字段都是单一属性的,不可再分。这个单一属性由基本类型构成,包括整型、实数、字符型、逻辑型、日期型等。
第二范式(2NF):数据库表中不存在非关键字段对任一候选关键字段的部分函数依赖(部分函数依赖指的是存在组合关键字中的某些字段决定非关键字段的情况),也即所有非关键字段都完全依赖于任意一组候选关键字。换句话说,就是需要确保数据库表的每一列都与主键相关。就是表里面只应该存储一种数据,而不是多种数据,例如订单表就应该存储订单,其中包含商品的id就行了,而不是存储一些商品的具体名称,价格等信息。避免数据冗余,增大维护成本。
第三范式(3NF):**在第二范式的基础上,数据表中如果不存在非关键字段对任一候选关键字段的传递函数依赖则符合第三范式。**所谓传递函数依赖,指的是如 果存在"A → B → C"的决定关系,则C传递函数依赖于A。因此,满足第三范式的数据库表应该不存在如下依赖关系: 关键字段 → 非关键字段 x → 非关键字段y。第三范式满足函数依赖集中,所有的候选关键字都是决定因素。换句话说,就是****确保数据库表的每一列直接依赖主键,而不是间接依赖主键。
BCNF范式:每一个决定因素都含有码
第四范式(4NF):限制关系模型中的属性之间不允许有非平凡且非函数依赖的多值依赖。
规范化
定义:一个第一级范式的关系模式通过模式分解可以转换为若干个高一级范式的关系模式的集合。
基本思想:逐步消除数据依赖中不合适的部分。实质上是概念的单一化。
消除非主属性对码的部分函数依赖
消除非主属性对码的传递函数依赖
消除主属性对码的部分和传递函数依赖
消除非平凡且非函数依赖的多值依赖
# 数据库设计
需求分析阶段
概念结构设计阶段
各子系统的E-R图之间的冲突
**属性冲突:**属性的取值单位冲突,属性值的类型,取值集合不同
命名冲突:
结构冲突:
同一对象在不同应用中具有不同的抽象。
同一实体在不同的子系统的E-R图中所包含的属性个数和属性排列次序不完全相同。
实体间的联系在不同的E-R图中为不同的类型。
逻辑结构设计阶段
E-R图向关系模型的转换
1:1联系可以转换为一个独立的关系模式,也可以与任意一端对应的关系模式合并。
- 如果是单独独立的关系模式,每个实体的码均是该关系的候选码
1:n联系可以转换为一个独立的关系模式,也可以与n端对应的关系模式合并。
- 如果转换为一个独立的关系模式,则关系的码为n端实体的码
- m:n联系可以转换为一个关系模式。各实体的码组成关系的码或者关系码的一部分。
数据库实施阶段
存储方法分为索引方法和聚簇方法
B+树索引存取方法的选择
如果一个或者一组属性经常在查询条件中出现
如果一个属性经常作为最大值和最小值等聚集函数的参数
如果一个或者一组属性经常出现在连接操作的连接条件中
hash索引存取方法的选择
聚簇存取方法的选择:一个数据库可以建立多个聚簇,但是一个表只能有一个聚簇。
对经常在一起进行连接操作的关系可以建立聚簇。
如果一个关系的一组属性经常出现在相等条件比较中,该单个关系可以建立聚簇。
如果一个关系的一个或一组属性上的值重复率很高,则该单个关系可以建立聚簇。
当SQL语句中包含有与聚簇码有关的ORDER BY,GROUP BY,UNION,DISTINCT等子句或者短语时,使用聚簇特别有利。
数据库运行和维护阶段
# 事务与故障
事务的定义:用户定义的一个数据库操作序列,这些操作要么全做,要么全不做,是一个不可分割的工作单位。
事务和程序:程序中包含多个事务。
一个事务可以是一条SQL语句,一组SQL语句或者整个程序。
事务的ACID特性:
atomicity:原子性。事务中的诸操作要么都做,要么都不做。
consistency:一致性。事务执行的结果必须使得数据库从一个一致性状态变到另一个一致性状态。
- 假设某公司有两个账号A,B,公司现在想从A账号取出1万元,存入B公司。定义一个事务,包括上述两个操作,如果只做一个操作,逻辑上会发生错误,数据库处于不一致的状态。
isolation:隔离性。一个事务的执行不能被其他的事务打扰,并发执行的各个事务之间不能相互打扰。
duration:持续性。永久性,一个事务一旦提交,它对数据库中数据的改变是永久性的。接下来的操作或者故障不应该对已经执行的结果产生影响。
数据库恢复
数据转储
静态转储:在系统无运行事务时进行的转储操作,即在转储期间不允许对数据库进行任何的存取,修改活动。
动态转储:指转储期间允许对数据库进行存取或者修改。
海量转储:每次转储全部数据库。
增量转储:每次只转储上一次转储后更新过的数据。
登记日志文件
日志文件:用来记录事务对数据库的更新操作的文件。
事务故障恢复和系统故障恢复必须要使用日志文件。
在动态转储方式中必须建立日志文件,后备副本和日志文件结合起来才能有效地恢复数据库。
在静态转储的过程也可以建立日志文件。
登记日志文件的规则:登记的次序必须按照并发事务执行的时间次序;必须先写日志文件,后写数据库。
恢复策略
事务故障的恢复
反向扫描日志文件,查找该事物的更新操作。
对该事务的更新执行逆操作。
继续反向扫描日志文件,查找该事务的其他更新操作,做同样的处理。
如此处理下去,直到读到此事务的开始标记。
系统故障(软故障)的恢复
正向扫描日志文件,找到故障发生前已提交的事务,将事务标识记入重做队列。同时找出故障发生时尚未完成的事务,并将其事务标识记入撤销队列。
对撤销队列中的每个事务进行撤销处理。
对重做队列中的每个事务进行重做处理。
介质故障(硬故障)的恢复
重装数据库。
重做已完成的事务。
# 并发控制
并发控制带来的数据不一致性:
lost update(丢失修改):两个事务T1,T2同时读一个数据并且修改,T1先提交,T2后提交。但是T2提交的结果破坏了T1提交的结果,导致T1的修改被丢失。丢失修改指一个事务的更新操作被另外一个事务的更新操作替换。
non-repeatable read(不可重复读):事务T1读取数据后,此时T2读取同一数据。T2对其进行修改后执行更新操作并且将其写回数据库。但是此时T1想要校对重读数据,但是T1无法再现前一次的读取结果。
dirty read(读脏数据)不正确的数据:事务T1修改了某一个数据将其写回磁盘,事务T2读取同一个数据后,由于T1因为某些原因撤销了刚刚的修改,这时被T1修改后的数据恢复了原值。T2读到的数据就和数据库中的数据不一致。读脏数据指在不同的事务下,当前事务可以读到另外事务未提交的数据。例如:T1 修改一个数据但未提交,T2 随后读取这个数据。如果 T1 撤销了这次修改,那么 T2 读取的数据是脏数据。
封锁粒度
MySQL 中提供了两种封锁粒度:行级锁以及表级锁。
应该尽量只锁定需要修改的那部分数据,而不是所有的资源。锁定的数据量越少,发生锁争用的可能就越小,系统的并发程度就越高。
但是加锁需要消耗资源,锁的各种操作(包括获取锁、释放锁、以及检查锁状态)都会增加系统开销。因此封锁粒度越小,系统开销就越大。
在选择封锁粒度时,需要在锁开销和并发程度之间做一个权衡。
基本的封锁类型:
排它锁(写锁,X锁):事务T对数据对象A加上X锁,只允许T读取和修改数据A,其他任何事务都不能对A加任何类型的锁,直到T释放A上的锁。
共享锁(读锁,S锁):事务T对数据对象A加上S锁,只允许T读取数据A,其他事务只能对A加S锁不能加X锁,直到T释放A上的锁。其他事务只能读A,不能修改A
封锁协议(保证数据的一致性)
一级封锁协议:防止了丢失修改
事务T在修改数据R之前必须先对其加X锁,直到事务结束才释放。
可以解决丢失修改问题,因为不能同时有两个事务对同一个数据进行修改,那么事务的修改就不会被覆盖。
二级封锁协议:新一步防止读脏数据
在一级封锁协议上增加事务T在读取数据R之前必须先对其加S锁,读完后即可释放S锁。
可以解决读脏数据问题,因为如果一个事务在对数据 A 进行修改,根据 1 级封锁协议,会加 X 锁,那么就不能再加 S 锁了,也就是不会读入数据。
三级封锁协议:进一步防止不可重复读
在一级封锁协议基础上增加事务T在读取数据R之前先对其加S锁,直到事务结束后才释放。
可以解决不可重复读的问题,因为读 A 时,其它事务不能对 A 加 X 锁,从而避免了在读的期间数据发生改变。
活锁和死锁