32554 words
163 minutes
数据库复习

第一章 绪论#

数据库系统概述#

  • 数据
    • 数据是信息的符号表示或载体,信息则是数据的内涵,是对数据的语义解释
  • 数据库
    • 数据库是长期存储在计算机内、有组织的、可共享的大量数据的集合
    • 数据是数据库中存储的基本对象
    • 数据库的基本特征:
      • 数据按一定的数据模型组织、描述和存储
      • 可为各种用户共享
      • 冗余度小
      • 数据独立性高
      • 容易扩展
  • 数据库管理系统
    • DBMS是对数据库进行管理的大型系统软件,是数据库系统的核心组成部分
      • 位于用户与操作系统之间的一层数据管理软件
      • 是基础软件,是一个大型复杂的软件系统
    • 用途:科学的组织和存储数据、高效的获取和维护数据
    • 用户在数据库系统中的一切操作,包括数据定义、查询、更新一集各种控制,都是通过DBMS进行的
    • 主要功能:
      • 数据定义
      • 数据组织、存储和管理
      • 数据操纵功能
      • 数据库的事务管理和运行管理
      • 数据库的建立和维护功能(实用程序)
      • 其它(如和其它系统的通信、交换)
  • 数据库系统
    • 构成
      • 数据库
      • 数据库管理系统(及开发工具)
      • 应用系统
      • 数据库管理员
    • 目的:
      • 给用户提供整体数据的抽象视图,将磁盘上的所有物理数据集合抽象成整体结构化的虚拟数据,隐藏了细节
    • 文件系统与数据库系统的区别
      • 文件系统,关注的是系统功能的设计,因此程序设计处于主导地位,数据服从于程序设计
      • 数据库系统阶段,数据的结构设计成为信息系统首先关心的问题
    • 数据库系统的特点:
      • 数据结构化
        • 整体结构话是数据库的主要特征之一.数据面向全组织,不仅数据内部结构化,整体是结构化的,数据之间具有联系
        • 数据库中实现的事数据的真正结构化
          • 数据的结构用数据模型描述,无需程序定义和解释
          • 数据可以变长
          • 数据的最小存取单位是数据项
      • 数据的共享性高,冗余度低,易扩充
        • 数据面向整个系统,数据集中管理,冗余度低
        • 节省存储空间,减少存取时间,避免数据之间的不一致性
        • 每个应用自己选数据库的子集
        • 数据库中并非完全消除荣誉.有时为了提高数据的存取效率,可保留多个副本
      • 数据独立性高
        • 逻辑独立性:数据总体逻辑结构改变,数据的局部逻辑结构不变
        • 无力独立性:数据的存储结构改变,数据的逻辑结构不变,从而应用程序也不需要改变
      • 数据由DBMS统一管理和控制
        • 统一的数据管理和控制功能:
          • 安全性
          • 完整性
          • 并发控制
          • 数据库恢复

数据模型#

数据模型:是一种描述数据、数据联系、数据语义及一致性约束的抽象工具,对显示世界数据特征的描述

  • 概念模型

    • 按照用户的观点对数据建模
      • 特点:语义表达能力强、便于直接表示应用语义、简单、清晰、易于理解
    • e.g. E-R模型
  • 信息学基本概念

    • 实体entity:客观存在可相互区别的事物、事件和概念
    • 属性Attribute:实体具有的特征
    • 码/键key:唯一标识一个实体集中任何实体值又不含多余属性的属性集
    • 实体型entity type:具有相同特征和性质的实体与属性命名序列
    • 实体值entity value:实体型的具体实例
    • 实体集entity set:具有相同类型及相同性质(属性)的实体集合
    • 联系:一对一、一对多、多对多
  • 数据模型的组成要素

    • 数据结构:描述数据库的组成对象及对象之间的关系
      • 描述系统的静态特性
      • 数据结构是所研究的对象类型的结合,是刻画一个数据模型性质最重要的方面
    • 数据操作:对数据库中各种对象(型)对实例(值)允许执行的操作的集合,包括操作及有关的操作规则
      • 描述系统的动态特性
      • 对数据库中各种数据操作的集合,包括操作及相应的操作规则
      • 数据模型必须定义这些操作的确切含义、操作规则以及实现操作的语言
    • 数据的约束条件
      • 是一组完整性规则的集合
      • 完整性规则是给定的数据模型中数据及器联系所具有的制约和遗存规则,用以限定符合数据模型的数据库状态以及状态的变化,以保证数据的正确、有效、相容
      • 数据模型还应该提供定义完整心约束条件的机制,以反映具体应用所涉及的数据结构必须遵守的特定的语义约束条件
  • 层次模型

    • 用树形结构表示实体及实体间联系
    • 特点:
      • 节点的双亲是唯一的:根节点没双亲,其它节点只有一个双亲
      • 只能直接处理一对多的实体联系
      • 每个记录类型可以定义一个排序字段,也称为码字段
      • 任何记录值只有按其路径查看时,才能显出它的全部意义
      • 没有一个子女记录值能够脱离双亲记录值而独立存在
    • 存储结构
      • 邻接法:前序遍历记录
      • 子女-兄弟链接法
      • 层次序列链接发
  • 网状模型

    • 特征
      • 可以有多个节点无父节点
      • 至少有一个节点有多个父节点
  • 关系模型

    • 关系必须是规范化的,满足一定的规范条件
      • 最基本的规范条件:关系的每一个分量必须是一个不可分的数据项,不允许表中还有表
    • 数据操作是集合操作,操作对象和操作结果都是关系,即若干元组的集合
      • 查询、插入、删除、更新
    • 存取路径对用户隐蔽,用户只要指出“干什么”,不必详细说明“怎么干”
    • 关系的完整性约束条件
      • 实体完整性
      • 参照完整性
      • 用户定义的完整性

数据库系统结构#

  • 数据模型中的“型”和“值”
    • 型:对某一数据的结构和属性的说明
    • 值:型的具体赋值

数据库系统模式的概念#

  • 模式schema
    • 数据库中全体数据的逻辑结构和特征的描述
    • 仅仅是型的描述,与具体的值无关
    • 反应的是数据的结构及其联系
    • 模式是相对稳定的
  • 实例Instance
    • 模式的一个具体值;反应数据库某一时刻的状态
    • 同一个模式可以有很多实例
    • 实例随数据库中数据的更新而变动

数据库系统的三级模式#

模式、外模式、内模式,三级模式之间有两级映像

提高了数据的逻辑独立性和物理独立性

  • 模式(逻辑模式)(schema)
    • 数据库中全体数据的逻辑结构和特征的描述
    • 所有用户的公共数据视图——全局逻辑视图,综合了所有用户的需求
    • 一个数据库只有一个模式
    • 模式的地位:是数据库模式结构的中间层,独立于数据库的其它层次
    • 定义:
      • 数据的逻辑结构(数据项的名字、类型、取值范围等)
      • 数据之间的联系
      • 数据有关的安全性、完整性要求
    • 模式一般由多个“记录”组成,包含数据库的所有信息
    • 设计数据库模式结构应该首先确定数据库的逻辑模式
    • 模式的作用是为了支持数据的少冗余共享
  • 外模式(子模式subschema、用户模式)
    • 数据库用户使用的局部数据的逻辑结构和特征的描述
    • 数据库用户的数据视图,面向具体的应用程序,是与某一应用有关的数据的逻辑标识
    • 定义再逻辑模式之上
    • 独立于存储模式和存储设备
    • 当应用需求发生较大变化,相应外模式不能满足视图要求时,该外模式就得做相应改动
    • 设计外模式时应充分考虑到应用的扩充性
    • 地位:介于模式与应用之间
      • 模式与外模式的关系:一对多
        • 外模式通常是模式的子集
        • 一个数据库可以由多个外模式。
        • 对模式中同一数据,再外模式中的结构、类型、长度、保密级别等都可以不同
      • 外模式与应用的关系:一对多
        • 同一外模式页可以为某一用户的多个应用系统锁时使用
        • 但一个引用程序只能使用一个外模式
    • 用途:
      • 支持不同用户建立适应局部应用特征的结构,每个用户只能看见和访问锁对应的外模式中的数据
      • 简化应用处理
      • 提高安全性,保证数据库安全性的一个有力措施
  • 内模式(internal schema,存储模式storage schema,物理模式)
    • 是数据物理结构和存储方式的描述
    • 是数据在数据库内部的标识方式
    • 一个数据库只有一个内模式

数据库的二级映像与数据独立性#

二级映像在DBMS内部实现这三个抽象层次的联系和转换

  • 外模式/模式映像:定义某一个外模式和模式之间的对应关系

    • 作用:保证数据的逻辑独立性
      • 当模式改变时,数据库管理员修改有关的外模式/模式影响,使外模式保持不变
      • 应用程序使依赖数据的外模式编写的,所以应用程序不必修改,保证了数据与程序的逻辑都要理性,简称数据的逻辑独立性
  • 模式/内模式映像:定义了数据全局逻辑结构与存储结构之间的对应关系

    • 数据库中模式/内模式映像使唯一的
    • 该映像定义通常包含在模式描述中
    • 保证数据的物理独立性:
      • 当数据库的存储结构改变了,数据库管理员修改模式/内模式映像,使模式保持不变
      • 存储结构变化的映像被限制在模式之下,这使数据的存储结构和存储方法独立于应用程序而不受影响。保证了数据与程序的物理独立性,简称数据的物理独立性。
  • 三级模式结构的优点

    • 保证数据的独立性(物理独立性&逻辑独立性)
    • 简化了用户接口:
      • 按照外模式编写应用系统或敲入命令,不需要了解数据库内部的存储结构,
    • 有利于数据共享
      • 在不同的外模式下可由多个用户共享系统中数据,减少了数据冗余
    • 利于数据安全保密
      • 在外模式下根据要求操作,不能对限定的数据操作,保证了其它数据的安全

第二章 关系数据库#

关系数据库结构及形式化定义#

关系#

  • 单一的数据结构——关系

    • 显示世界的实体以及实体间的各种联系均用关系来标识
  • 逻辑结构——二维表

    • 从用户角度,关系模型中数据的逻辑结构是一张二维表
  • 关系模型建立在集合代数的基础上

    • 域(domain)
    • 笛卡尔积
    • 关系
  • 域:是一组具有相同数据类型的值的集合

    • 域中锁包含的值的个数称为域的基数
    • 关系中用域标识属性的取值范围
  • 笛卡尔积

    • 给定一组域D1,D2,...,DnD_1,D_2,...,D_n,这些域中可以有相同的,则D1,D2,...,DnD_1,D_2,...,D_n的笛卡尔积为
    • D1×D2×...×Dn={(d1,d2,...,dn)diDi,i=1,2,...,n}D_1 \times D_2 \times ... \times D_n = \{(d_1,d_2,...,d_n) | d_i \in D_i, i=1,2,...,n \}
    • 笛卡尔积中每一个元素(d1,...,dn)(d_1,...,d_n)叫做一个n元组
    • 笛卡尔积元素(d1,...,dn)(d_1,...,d_n)中的每一个值did_i叫做一个分量
    • DiD_i为有限集,基数mim_i,则D1×D2×...×DnD_1 \times D_2 \times ... \times D_n的基数M为M=Πi=1nmiM=\Pi _{i=1}^{n}m_i
    • 笛卡尔积是一个集合;是所有域的所有取值的一个组合
    • 不能重复
  • 关系

    • 笛卡尔积的自己叫做在域D1,D2,...,DnD_1,D_2,...,D_n上的关系,用R(D1,...,Dn)R(D_1,...,D_n)表示
    • R是关系的名字,n是关系的度或目(Degree)
    • 关系中的每个元素称为元组
    • 关系中不同列可以对应相同的域,为了加以区分,必须对每列其一个名字,称为属性
    • n目关系必有n个属性
    • 候选码:
      • 若关系中的某一属性组的值能唯一地表示一个元组,若从属性组中去掉任意属性,它就不再具有这一性质,则称该属性组为候选码
      • 主码:若有一个关系又多个候选码,则选定其中一个为主码
        • 每个关系又且仅有一个主码
      • 主属性:候选码的诸属性
      • 非主属性或非码属性:不包含在任何候选码中的属性
    • 三类关系:
      • 基本关系(基本表或基表)
        • 实际存在的表,是实际存储数据的逻辑表示
      • 查询表
        • 查询结果对应的表
      • 视图表
        • 由基本表或其它视图表到处的表,是虚表,不对应实际存储的数据
    • 关系与二维表的区别:关系是规范化了的二维表中行的集合,为了使相应的数据操作简化,在关系模型中对关系做了限制
    • 基本关系的6大特性
      • 列是同质的(Homogeneous)
      • 不同的列可出自同一个域,其中的每一列称为一个属性,不同的属性要基于不同的属性名
      • 列的顺序无所谓,列的次序可以任意交换
      • 任意两个元组的候选码不能相同
      • 行的顺序无所谓,行的次序可以任意交换
      • 分量必须取原子值,即每个分量是都不可分的数据项

关系模式#

  • 关系模式是型,相对静态,稳定
  • 关系是值,是关系模式在某一时刻的状态或内容,是动态的、随时间不断变化的
  • 关系模式是对关系的描述
    • 元组集合的结构:
      • 属性构成
      • 属性来自的域
      • 属性与域之间的映像关系
    • 元组语义以及完整性约束条件
    • 属性间的数据依赖关系集合
  • 关系模式,记作R(U,D,DOM,F)
    • R:关系名
    • U中的属性名集合
    • D:属性组U中属性锁来自的域(取值范围)
    • DOM:属性到域的映像集(属性类型、长度)
    • F:属性间数据的依赖关系集合

关系的完整性#

实体完整性#

  • 在关系中的所有元组在码上的取值满足
    • 主属性非空
    • 主码各不相同

参照完整性#

  • 若属性(组)F是基本关系R的外码,它域基本关系S的主码Ks相对应(R和S不一定是不同的关系),则uiyuR中每个元组在F上的值必须为
    • 空值(F的每个属性值均为空)
    • S中某个元组的主码值

用户定义的完整性#

关系代数#

传统的集合运算#

除笛卡尔积外,要求参加运算的关系必须具备相容性

  • 相容性

    • 具有相同的度n
    • R中的第i个属性和S中的第i个属性来自同一个域
  • 笛卡尔积

专门的关系运算#

  • 选择
    • σF(R)={ttRF(t)=true}\sigma _F(R) = \{t|t\in R \cap F(t)=true \}
    • 其中,σ\sigma为选择运算符,F为条件表达式。σF(R)\sigma _F(R)表示从R中挑选满足公式F的元组所构成的关系
  • 投影
    • 从R中选择处若干属性列组成新的关系
    • πA(R)={t[A]tR}\pi _{A(R)}=\{t[A]|t \in R \}
    • 投影的结果要去掉相同的行(避免重复行)
      • 投影之后不仅取消了原关系中的某些列,还可能取消某些元组
  • 连接:从两个关系的笛卡尔积中选取满足连接条件的元组
    • 等值连接:从关系R域S的广义笛卡尔积中选取A、B属性值相等的哪些元素
    • 自然连接:特殊的等值连接
      • 两个关系中进行比较的分量必须是相同的属性组
      • 在结果中把重复的属性列去掉
      • 当R和S无相同属性时,自然连接就是做笛卡尔积
      • 本质是将两张由关联的表,按照元组之间在属性B(外码)上的等值关系,合并为一张表
      • 问题:会丢失信息,如丢失一个未选课的学生
    • 外连接:把舍弃的元组页保存在结果关系中,而在其它属性上填空值null
    • 左外连接:只把左边关系R中要舍弃的元组保留(left join)
    • 右外连接:只把右边关系S中要舍弃的元组保留(right join)
  • R÷SR\div S
    • T=π1,...,rs(R)T=\pi _{1,...,r-s}(R)
    • W=(T×S)RW=(T\times S)-R
    • V=π1,..,rs(W)V=\pi_{1,..,r-s}(W)
    • R÷S=TVR\div S=T-V
    • R÷S=π1,...,rs(R)π1,...,rs((π1,...,rs(R)×S)R)R\div S=\pi_{1,...,r-s}(R)-\pi _{1,...,r-s}((\pi _{1,...,r-s}(R)\times S)-R)

关系演算(不重要)#

  • 关系演算:以处理逻辑中的谓词演算为基础
  • 按谓词变元不同进行分类
    • 元祖关系演算:以远足变量作为谓词变元的基本对象
    • 域关系演算:以域变量作为谓词变元的基本对象

第三章 关系数据库标准语言SQL#

SQL概述#

  • SQL是非过程化语言
  • 核心动词
    • 数据查询(DQL): select
    • 数据定义(DDL): create, drop, alter
    • 数据操纵(DML): delete, update, insert
    • 数据控制(DCL): grant, revoke

SQL的基本概念#

  • 基本表(base table)

    • 独立存在的表,SQL中一个关系就对应一个基本表
    • 一个(或多个)基本表对应一个存储文件
    • 一个表可以带若干索引,索引也放在存储文件中
  • 存储文件(stored file)

    • 逻辑结构组成了关系数据库的内模式
    • 无力结构是任意的,对用户透明
  • 视图(view)

    • 从一个或几个基本表导出的表
    • 数据库中之存放视图的定义而不存放视图对应的数据,视图是一个虚表
    • 用户可以在视图上再定义视图
  • 在一个目录下可以建立多个模式

  • 在一个模式下可以建立多个关系表

数据定义#

SQL的数据定义语言DDL功能:模式定义、表定义、视图和索引定义

操作对象创建删除修改
模式create schemadrop schema
create tabledrop tablealter table
视图create viewdrop view
索引create indexdrop index
  • 层次化数据库对象命名机制
  • 1个DBMS实例:多个DB
    • 1个DB中:多个模式
      • 1个模式下:多个表、视图、索引

模式的定义与删除#

  • 定义模式
    • 语句
create schema <模式名> authorization <用户名>
[<表定义子句>|<视图定义子句>|<授权定义子句>];
  • 语义:为某用户创建一个模式.定义模式实际上定义了一个命名空间,其中可以定义该模式包含的数据库对象,例如基本表、视图、索引等
  • 在create schema中可以接受create table, create view和grant子句
  • 删除模式
drop schema <模式名><cascade|restrict>
  • cascade(级联):删除模式等同事把该模式中所有的数据库对象全部删除
  • restrict(限制):如果该模式中定义了下属的数据库对象(如表,视图等),则拒绝该删除语句的执行.当该模式中没有任何下属的对象时才能执行

基本表的定义、删除与修改#

  • 定义基本表 DDL不仅运行定义一组关系,也要说明每个关系的信息
    • 每个关系的模式
    • 每个属性的值域
    • 完整性约束
    • 每个关系的安全性和权限
    • 每个关系需要的索引集合
    • 每个关系在磁盘上的无力存储结构
  • 基本表的定义(创建)
create table <表名> (
<列名><数据类型>[列级完整性约束条件]
[,<列名>,<数据类型>[列级完整性约束条件]]
...
[,<表级完整性约束条件>]
)
  • <表名>:所要定义的基本表的名字
  • <列名>:组成该表的各个属性(列)
  • <列级完整性约束条件>:设计相应属性列的完整性约束条件
  • <表级完整性约束条件>:设计一个活多个属性列的完整性约束条件
  • 创建基本表
create table 表名(
列名 数据类型 [default 缺省值] [not null]
[,列名 数据类型 [default 缺省值][not null]...]
[, primary key(列名[,列名]...)]
[foreign key(列名[,列名]...) references 表名(列名[,列名]...)]
[, check (条件表达式)]
);
  • 常用的完整性约束
    • 主码: primary key
    • 唯一性约束: unique
    • 非空值约束: not null
    • 参照完整性约束: foreign key
    • 自定义的完整性约束: check(逻辑表达式)

数据类型#

数据类型含义
char(n)长度为n的定长字符串
varchar(n)最大长度为n的变长字符串
int长整数
smallint短整数
numeric(p,d)定点数,由p位数字(不包括符号、小数点)组成,小数点后有d位
real取决于机器精度的浮点数
double precision取决于机器精度的双精度浮点数
float(n)浮点数,精度至少为n位数字
date日期,包含年、月、日,格式为YYY-MM-DD
time时间,格式HH:MM
interval两个date或time类型数据之间的差

模式与表#

  • 每一个基本表都属于某一模式
  • 一个模式包含多个基本表
  • 定义基本表所属模式
    • 在表名中明显给出模式名
      • create table "S-T".Student (...);
    • 在创建模式语句中同时创建表

修改数据表#

alter table <表名>
[add <新列名><数据类型>[完整性约束]]
[add <表级完整性约束>]
[drop [column]<列名>[cascade|restrict]]
[drop constraint <完整性约束名>[cascade|restrict]]
[alter column <列名><数据类型>];
  • 语义:
    • 对名为<表名>的表做add、drop或alter column操作
    • add可以增加一个新的列
    • drop只能删除表上的完整性约束?(~也可以删除列啊)
    • alter只能更改列上的数据类型

删除基本表#

drop table <表名>[restrict|cascade];
  • restrict
    • 欲删除的基本表不能被其他表的约束所引用
    • 如果存在依赖该表的对象,啧此表不能被删除
  • cascade:删除的时候,相关的依赖对象一起删除(包括其他表和视图)

索引的建立与删除#

  • 建立索引的目的:加快查询速度
  • 谁建立索引
    • DBA或表的属主
    • DBMS一般会自动为主码和uniqe属性的列创建索引
  • 谁维护索引自动完成
  • 谁使用索引用户不直接使用索引. DBMS自动选择是否使用索引以及使用哪些索引

建立索引#

create [unique][cluster] index <索引名>
on <表名>(<列名>[<次序>][,<列名>[<次序>]]...);
-- 其中,<次序>指升序或降序,缺省为升序
  • 坏处:过多或不当的索引会耗费空间,且降低插入、删除、更新的效率
  • 说明:
    • unique(单一索引):
      • 唯一索引,表示索引项值对应元祖唯一,不允许存在索引值相同的两行
    • cluster(聚集索引):
      • 索引项的顺序与表中记录的物理顺序一致,表中如果有多个记录在索引字段上相同,这些记录构成一簇,只有一个索引值
    • 在最经常查询的列上建立聚簇索引以提高查询效率
    • 经常更新的列不宜建立聚簇索引

修改索引#

alter index <旧索引名> rename to <新索引名>

删除索引#

drop index <索引名>
-- 或
drop index <索引名> on <表名>

数据字典#

数据字典:关系 DBMS内部的一组系统表,记录数据库中所有的定义信息

数据查询#

  • select语句的基本句法 πA1,...,An(σF(R1×...×Rm))\pi _{A_1,...,A_n}(\sigma _F (R_1 \times ... \times R_m)) 对应的语句
select A1,...,An
from R1,...,Rm
where F
  • select语句的完整句法
select [all|distinc]<目标列表达式>[,<目标列表达式>]...
from <表名或视图名>[,<表名或视图名>]...
[where <条件表达式>]
[group by <列名> [having <条件表达式>]]
[order by <列名> [asc|desc]]
  • where子句称为行条件子句
  • group子句称为分组子句
  • having子句称为组条件子句
  • order子句称为排序子句

单表查询#

  • 字符匹配
    • 通配符
      • 百分号% 代表任意长度的字符串
      • 下划线_ 代表任意一个字符
      • escape” 表示""是一个换码字符
  • 对于空值的时候,只能是is null,不能用等号
  • 聚集函数
    • 计数
      • count([distinct|all]*):统计元祖个数
      • count([distinct|all]<列名>):统计一列中值的个数
    • 计算总和
      • sum([distinct|all]<列名>)
    • 计算平均值
      • avg([distinct|all]<列名>)
    • 最大值最小值
      • max([distinct|all]<列名>)
      • min([distinct|all]<列名>)
    • 集函数只能用于select子句和having子句中
    • 当集函数遇到null的时候,除了count(*),都跳过空值
  • where子句域having子句的区别:作用对象不同
    • where子句作用域于基本表或视图,从中选择满足条件的元组
    • having短语作用于组,从中选择满足条件的组

连接查询#

嵌套查询#

  • 子查询不能使用order by子句

  • 反应了SQL语言的结构化

  • 有些嵌套查询可以用连接运算代替

  • 应用场景:

    • 属于运算:该成员t是否属于某个select结果集合R;in谓词
    • 比较运算:该成员是否比某个select即中所有成员或至少一个成员大或小;
    • 逻辑运算:该成员是否能使得集合逻辑式成立;
  • 当子查询的返回值只有一个的时候,可以使用比较运算符将父查询和子查询连接起来

子查询执行方式#

  • 非相关子查询的执行顺序:
    • 首先执行子查询
    • 父查询设计的所有元组都与子查询的查询结果进行比较,以确定查询结果集合
  • 相关子查询的执行顺序
    • 首先选取夫查询表中的一个元组,内部的子查询利用此元组中相关的属性值进行查询
    • 然后夫查询根据子查询返回的结果判断此行是否满足查询条件,如果满足条件,则把该行放入父查询结果集合中
    • 重复执行以上,指导处理完夫查询表中的所有元组
  • 非相关子查询只执行一次;而相关子查询的执行次数是由夫查询表的行数决定的

带有exists谓词的子查询#

最重要的就是掌握双否表肯定

集合查询#

  • 并操作union
  • 交操作intersect
  • 差操作except

数据更新#

插入数据#

插入元组#

insert into 基本表[(列名[,列名]...)]values(元组值);

作用:将一条元组值插入到表中

查询结果的插入#

insert into <基本表名> [(<列名表>)] 子查询;

作用:将子查询返回的结果数据插入到表中。查询语句的目标列必须与into子句匹配

RDBMS在执行插入/更新语句时回检查所插元组是否破坏表上已定义的完整性规则,包括实体、参照和用户定义的完整性

删除数据#

delete from <表名>[where 条件表达式]

作用:从表中删除符合where子句中删除条件的元组;若where子句缺省,啧阐述表中所有元组

  • 不带条件的delete语句和drop table语句的区别
    • drop table语句删除表和表中的所有数据
    • delete语句指删除表中的数据,表仍然保留

带子查询的删除语句:

delete from sc
where sno in (
select sno
from student
where sdept='CS'
);

更新数据#

update <基本表名>
set <列名>=值表达式[,<列名>=值表达式...]
[where 条件表达式]

作用:对表中满足where条件的远足,按set子句修改相应列的值

也可以带字查询,语法和上面类似

视图#

  • 视图是从一个活几个基本表(或视图)中导出的一个虚表
    • 数据库中只存放视图的定义二不存放视图的数据,这些数据仍放在原来的基表中.当基表中的数据发生变化时从视图中查出的数据也随之改变了
    • 视图一经定义就可以对其进行查询,单对视图的更新操作有一定的限制

视图的定义#

建立视图#

create view 视图名[(列名,[列名]...)]
as 子查询
[with check option]
  • 说明: 视图的列名为可选项,缺省时,其列名即为字查询的查询目标列.但在以下情况下,视图列名不可省略
    • 视图由多个表连接得到,在不同的表中存在同名列,需要指定列名字
    • 当视图的列名为表达式或集函数的计算结果,而不是单纯的属性名时,需要制定列名
    • 在字查询中,不许使用order by子句,如果需要排序,则可在视图定义后,对视图查询时再进行排序
    • 如果指明了with check option选项,则在对视图进行更新时,所影响的元组必须满足视图定义中的where条件
  • 行列子集视图:从一个基本表中导出,只是去掉了某些行或列(保留原表的主码),这样的视图称为行列子集视图
  • 多表视图:从多个基本表或视图中导出
  • 带表达式的视图,即带虚拟列的视图
  • 分组视图,子查询带集函数和group by分组的视图

删除视图#

drop view <视图名> [cascade];

作用:从数据库中删除一个视图的定义信息,cascade表示把该视图和它导出的视图一起删除

查询视图#

  • 用户角度:查询视图与查询基本表相同
  • DBMS执行对视图的查询时
    • 首先进行有效性检查,检查查询设计的表、视图等是否在数据库中存在
    • 如果存在,则从数据字典中取出查询设计的视图的定义
    • 把定义中的子查询和用户对视图的查询结合起来,转换成等价的基本表的查询
    • 然后再执行这个经过修正的查询
  • 将对视图的查询转换为对基本表的查询的过程称为视图的消解

更新视图#

  • 视图的更新操作包括插入、修改和删除数据,语法格式同基本表的更新

  • 因为视图是一张虚表,所以对视图的更新,最终实际上是转换成对基本表的更新

  • 一些视图是不可更新的,因为这些视图的更新不能唯一地有意义地转换成对应基本表的更新

    • 字段由表达式或常数组哼,不允许执行insert和该字段上dupdate,但可以执行delete
    • 字段由机函数组成,不允许更新
    • 视图定义含有group by或distinct,不允许更新
    • 有潜逃查询,且内外查询使用相同表时,不允许更新
    • 定义中有多表链接时,不允许更新
    • 由不允许更新的视图导出的视图,不允许更新
  • 视图的作用

    • 简化用户的操作
    • 使用户能以多种角度看待同一数据
    • 对重构数据库提供一定程度的逻辑独立性
    • 是数据共享与保密的一种安全机制
    • 适当的利用视图可以更清晰的查询表达

第四章 数据库安全性#

安全性概述#

  • 定义:
    • 数据库的安全性是只保护数据库以防止不合法的使用所造成的数据泄漏、更改或破坏
  • 重要性
    • 数据库系统中大量数据集中存放,许多用户直接共享
    • 系统的安全保护措施是否有效是数据库系统的主要性能指标之一

数据库的不安全因素#

  • 非授权用户对数据库的恶意存取和破坏
    • 安全措施:用户身份鉴别、存取控制和视图等
  • 数据库中重要或敏感数据被泄漏
    • 安全措施:审计、日志、入侵检测等
  • 安全环境的脆弱性

数据库安全控制技术#

用户身份鉴别#

  • 系统提供的最外层安全保护措施
  • 系统提供一定的方式让用户标识自己的名字和身份,系统进行核实,通过鉴定后才提供系统使用权

存取控制#

  • 对于获得上机权的用户还要根据系统预先定义好的外模式(视图)或用户权限进行存取控制,保证用户只能存取他有权存取的数据
  • 方法
    • 定义用户权限,登记到DD中
    • 合法权限检查
  • 常用存取控制方法
    • 自主存取控制(Discretionary Access Control, DAC),C2级,灵活
      • 用户或DBA定义存取权限的一种控制策略,通过SQL的grant语句和revoce语句实现
      • 访问权限由两个要素组成:数据对象和操作.类型系统通过控制数据对象的访问权限防止非授权访问
      • 缺点:
        • 可能存在数据的“无意泄漏”
        • DAC容易受到特洛伊木马攻击
        • 原因:这种机制仅仅通过对数据的存取权限来进行安全控制,而数据本身并没无安全性标记
        • 解决:对系统控制下的所有主客体实施强制存取控制策略
    • 强制存取控制(Mandatory Access Control, MAC),B1级,严格

授权与回收#

授权grant#

grant <权限>[,<权限>]...
[on <对象类型><对象名>]
to <用户>[,<用户>]...
[with grant option]
  • 语义:将对指定操作对象的指定操作权限授予指定用户
  • with grant option: 若指定:可以再授予;否则,不能传播
  • 不允许循环授权

回收revoke#

revoke <权限>[,<权限>]...
[on <对象类型><对象名>]
from <用户>[,<用户>]...
[cascade|restrict]

创建数据库模式的权限#

create user <username>
[with][dba|resource|connect];

数据库角色#

  • 角色:被命名的一组与数据库操作相关的权限
  • 角色是权限的集合
  • 可以为一组具有相同权限的用户创建一个角色,简化授权的过程

角色的创建

create role <角色名>

给角色授权

grant <权限>[,<权限>]...
on <对象类型>对象名
to <角色>[,<角色>]...

将一个角色授予其他的角色或用户

grant <角色1>[,<角色2>]...
to <角色3>[,<用户1>]...
[with admin option]

角色权限的收回

revoke <权限>[,<权限>]...
on <对象类型><对象名>
from <角色>[,<角色>]...

强制存取控制#

管理员管理访问控制、制定策略,用户不能直接感知或进行控制

  • 实体类别
    • 主体:系统中的活动实体,包括用户和用户的进程
    • 客体:系统中的被动实体,受主体操纵的基表、索引、视图等
  • 敏感度标记(label):
    • 绝密
    • 机密
    • 可信
    • 公开
  • 强制存取控制规则:
    • 仅当主体的许可证级别大于或等于客体的密级时,该主体才能读相应的客体
    • 仅当主体的许可证级别等于或小于客体的密级时,该主体才能写相应的客体
  • 优点
    • 禁止拥有高许可证级别的主体更新低密级的数据对象,从而保证了敏感数据的可靠性
    • 禁止低许可证级别的主体浏览高密级的数据,避免了敏感数据的泄漏
    • MAC对数据本身进行密级标记,无论数据如何复制,标记与数据是不可分割的整体.只有符合密级标记的要求的用户才可以操作响应数据,提高了安全性级别
  • 兼容关系
    • 安全级别之间具有篇序乡下兼容关系,较高安全性级别的安全保护措施要包含较低安全级别的所有保护措施,同时应提供更多完善的保护能力.因此实现MAC必须先实现DAC,DAC和MAC共同构成DBMS的安全机制

视图机制#

  • 用户可以通过视图访问基表,也可以直接访问基表,但对安全级别要求较高的数据一般通过视图进行访问,从而避免直接访问基表中其他数据
  • 对于终端用户,虽然数据库中的数据是面向全局的,但通过视图隔离他只能看到专门为他定义的视图中与自己相关的数据.其他与他无关的数据被子模式,即视图隔离或屏蔽了

审计#

  • 审计:对用户使用系统资源情况的登记和审查
    • 审计日志:将用户对数据库的所有操作记录在上面
    • DBA可以利用审计日志,找出非法存取数据的人、时间和内容
    • C2以上安全级别的DBMS必须具有
  • 审计分类
    • 用户级审计
      • 用户对自己拥有的数据库对象上发生的操作进行审计
      • 记录所有用户对这些表或视图的一切成功和(或)不成功的访问要求以及各种类型的SQL操作
    • 系统级审计
      • DBA设置
      • 监测成功或失败的登陆请求
      • 监测grant和revoke操作以及其他数据库级权限下的操作
  • audit语句:设置审计功能
  • noaudit语句:取消审计功能

数据机密#

第五章 数据库完完整性#

  • 数据库的完整性
    • 数据的正确性和相容性
      • 正确性指数据库中数据与现实世界的实际情况是享福的
      • 相容性指数据库中数据自身不存在自相矛盾的现象
  • 完整性 VS 安全性
    • 完整性
      • 防止数据库中存在不符合语义的数据,也就是防止数据库中存在不正确的数据
      • 防范对象:不合语义、不正确的数据
    • 安全性:
      • 保护数据库防止恶意的破坏和非法的存取
      • 防范对象:非法用户和非法操作
  • DBMS的完整性控制功能
    • 为用户提供定义完整性约束条件的机制
    • 监督系统中执行的操作是否违反完整性限制条件(insert, delete, update)
    • 对违反完整性约束的情况进行相应处理(拒绝执行/级联操作)

实体完整性#

  • 实体完整性在关系模型中通过关系的主码来体现
  • 有列级约束和表级约束两种,如果主码由多个列构成,只能用第二种方法定义主码
  • 实体完整性的检查
    • 对基表插入数据或对主码列进行更新时,DBMS将自动对该操作进行实体完整性检查,包括
      • 主码值是否唯一,否则拒绝执行该操作
      • 各主码列的值是否为空,否则拒绝执行该操作

参照完整性#

  • 参照完整性在关系模型中通过关系的外码来想体现
  • 参照完整性的检查
被参照表参照表违约处理
可能破坏参照完整性插入元组拒绝
可能破坏参照完整性修改外码值拒绝
删除元组可能破坏参照完整性拒绝/级联删除/设置为空值
修改主码值可能破坏参照完整性拒绝/级联修改/设置为空值
  • 在子表中插入元组
    • 仅当父表中存在与插入元组相应的元组时,系统执行在子表中插入元组的操作,否则拒绝此插入操作
  • 修改子表外码
    • 如果父表中存在待修改的值,则执行;否则不允许执行此类修改操作
  • 修改父表主码(若子表中由相关参照记录)
    • 拒绝修改:拒绝执行
    • 级联修改:将子表中相关记录在外码上的值一起自动修改
    • 置空修改:将子表中相关记录在外码上的值全部置为null
  • 删除父表元组(若子表中由相关参照记录)
    • 拒绝删除
    • 级联删除:删除附表中元组的同时,自动删除子表中的相关元组
    • 置空删除:删除附表中元组的同时,自动将子表中的相关元组的外码置空

指定在删除或修改父表时的违约处理动作:
在定义参照完整性约束的时候,可同时指定删除或修改时的违约处理动作,如not action,set nullcascade。缺省动作为not actionno action是据绝操作的意思哦

用户定义的完整性约束#

  • 空值约束(列级)
    • not null
  • 唯一性约束(列级/表级)
    • unique
  • check约束(列级/表级)
    • check(<条件表达式>)
    • 如果条件表达式涉及的对象只有一个,那么就可以使用列级

完整性约束命名子句#

  • 完整性约束与列一样是关系模式的构成元素
  • 关系中的列是必须命名的,但是约束不一定要命名
constraint <约束名><约束说明>

其中,约束说明可以是primary key子句,foreign key子句,not null子句,unique子句和check子句

alter table语句中通过约束名删除约束,也可添加新的约束

alter table S drop constraint C1
alter table S add constraint C2 check(Age>=15 and age <=30)

增加新约束,数据库不会对已经在库里的数据检查一遍约束条件

断言#

  • 申明性断言:指定更具一般性约束,可涉及多表或聚集操作的交复杂的完整性约束
create assertion <断言名><check子句>;

触发器#

触发器是定义在基表上的一种数据库对象,它指定:在执行对表的某些操作的时候,另一些操作也同时被执行

定义触发器#

create trigger <触发器名>
[before|after]<触发事件>on<表名>
for each {row|statement}
[when <触发条件>]
<触发动作体>;
  • 说明:
    • <触发事件>:可以是insert,delete,update,或者这些事件的组合,update后面可以带of<触发列,…>,指明只当哪些列被修改时才激活触发器。before和after表示触发器是在触发事件之前还是之后被激活
    • for each row表示该触发器为行级触发器,触发事件没映像一条元组都将激活一次触发器
    • for each statement表示该触发器为语句级触发器,触发事件只激活一次触发器
  • DBMS如何执行触发器
    • 触发器被激活后,先检查<触发条件>,当其值为真时,<触发动作体>才执行;如果没有指定<触发条件>,则<触发动作体>在触发器被激活后立即执行
    • <触发动作体>是一段程序,如果触发器是行级触发器,则这段程序中还可以使用new和old分别引用触发事件发生前后的元组值

激活触发器#

  • 触发器的执行,是由触发事件激活的,并由数据库服务器自动执行
  • 一个数据表上可能定义了多个触发器,同一个表上的多个触发器激活时遵循以下顺序
    • 执行该表上的before触发器
    • 激活触发器的sql语句
    • 执行该表上的after触发器
  • 多个触发器执行时,这些触发器按创建事件顺序依次执行
  • 任意触发器的执行失败都将中止整个操作

触发器的撤销#

drop trigger <触发器名> on <表名>

说明:触发器必须是一个已创建的触发器,并且只能由具有相应权限的用户删除

注:触发器是与表相关联的,因此,表的撤销将引起该表上的所有触发器同时被撤销

触发器的作用#

  • 强制实现由逐渐和外键所不能保证的参照完整性和数据的一致性
  • 实现比check语句更复杂的约束(涉及多表)
  • 找到数据修改前后表状态的差异,并基于此差异采取行动
  • 级联运行修改数据库中相关表,自动触发相关操作
  • 跟踪变化,禁止/回滚不合规则的操作,防止非法修改数据
  • 返回自定义的错误消息(约束做不到)
  • 自动调用存储过程

第六章 关系数据理论#

引言#

  • 一个完整的关系模式用五元组表示:R(U, D, DOM, F)
    • R:关系名称
    • U:一组属性
    • D:U中属性所来自的域
    • DOM:属性到域的映射
    • F:属性组U上的一组数据依赖
  • 关系模式涉及中起主要作用的是U和F,简化的关系模式为三元组R<U,F>
    • 表示:仅当U上的一个关系r满足F时,r称为关系模式R<U,F>上的一个关系

规范化#

函数依赖#

定义:设R(U)是一个属性集U上的关系模式,X,YUX,Y\subseteq U,r是R(U)上的任意一个关系,如果成立 t,sr,ift[X]=s[X],theny[Y]=s[Y]\forall t,s \in r, if t[X]=s[X], then y[Y]=s[Y] 则称“X函数确定Y”或“Y函数依赖于X”,记作X->Y。X称为这个函数依赖的决定属性集。

  • 说明
    • 函数依赖不是指关系模式R的某个或某些关系实力满足的约束条件,而是指R的所有瓜西实力均要满足的约束条件
    • 函数依赖是语义范畴的概念,只能根据语义来确定一个函数依赖,而不能按照其形式定义来证明一个函数依赖是否成立
    • 函数依赖关系的存在于时间无关
    • 属性间联系于函数依赖的对应关系
      • 1:1联系:存在函数依赖X->Y,且Y->X,即X<—>Y
      • 1联系:存在函数依赖X->Y,但不存在Y->X
      • m联系:不存在函数依赖
  • 平凡函数依赖与非平凡函数依赖
    • 平凡函数依赖
      • 设有关系模式R(U,F),X,Y都是U的子集,若X->Y,YXY \subseteq X,则称X->Y是平凡函数依赖
    • 非平凡函数依赖
      • 设有关系模式R(U,F),X,Y都是U的自己,若X->Y,YXY \subsetneq X,则称X->Y是非平凡函数依赖
    • 说明:对于任何R,平凡函数依赖总是成立的。
  • 完全函数依赖于部分函数依赖
    • 定义:设关系模式R(U),U是属性全集,X和Y是U的子集
      • 如果X->Y,并且对于X的任何一个真子集X’,都有X’!->Y,则称Y完全函数依赖于X,记作X-F>T
      • 如果对于X的某个真子集X’,有X’->Y,则称Y部分函数依赖于X,记作X-P>Y
  • 传递函数依赖
    • 定义:再关系模式R(U)中,如果X->Y,Y->Z,且YX,YX,ZYY \subsetneq X,Y \subsetneq X, Z \subsetneq Y,则称Z传递函数依赖于X,记作X-T>Z
    • 注:如果还有Y->X,即X<—>Y,则Y直接依赖于X

#

  • 设K为关系模式R<U,F>中的属性或属性组合,若K-F>U,则K称为R的一个候选码。若关系模式R有多个候选码,则选定其中的一个作为主码
    • 主码:任意候选码之一
    • 主属性:包含在任何一个候选码中的属性。
    • 超码:若K-P>U,则K称为超码
  • 关系模式R中属性或属性组X并非R的码,但X是另一个关系模式的码,则称X是R的外部码,也称外码
  • 主码和外码一起提供了表示关系间联系的手段

范式#

  • 范式:关系数据库的规范化过程中为不同程度的规范化要求设立的不同标准
  • 通过模式分解将一个低级范式转换为若干个高级范式的过程陈佐规范化

第一范式1NF#

  • 如果关系模式R,其所有的属性均为简单属性,即每个属性都是不可再分的,则称R属于第一范式,简称1NF,记作R1NFR \in 1NF
  • 第一范式是最基本的规范形式,满足这个条件的关系称为规范化关系
  • 关系DBS中,所有关系模式都必须是1NF
  • 将非1NF转换为1NF的方法:
    • 去掉嵌套属性上层
    • 重写行交叉处的值
  • 1NF存在的问题:数据容易,具有插入异常、删除异常、更新复杂
    • 原因:非主属性部分函数依赖于候选码
  • 解决方法(投影分解)
    • 消除非主属性对码的部分FD(函数依赖)
      • 所有完全函数依赖于码的属性组成一个关系模式
      • 所有部分函数依赖于码的属性组成一个关系模式

2NF#

  • 如果关系模式R1NFR \in 1NF,且每个非主属性都完全函数依赖于R的码,则称R属于第二范式2NF,记作R2NFR \in 2NF
  • 即:不能存在仅依赖主关键字一部分的属性,如果存在,那么这个属性的主关键字的这一部分应该分离出来形成一个新的实体,新实体与原实体之间是一对多的关系。简而言之,第二范式就是属性完全依赖于主键。
  • 推论:若R1NFR \in 1NF,且其候选码为单个属性,则R2NFR \in 2NF
  • 2NF存在的问题:非主属性对码的传递依赖
  • 解决方法:投影分解,消去非主属性对码的传递依赖

3NF#

  • 如果关系模式R(U,F)1NFR(U,F) \in 1NF,其中不存在码X,属性组Y及非主属性Z(ZYZ \subseteq Y),使得X->Y(Y !-> X), Y!->Z成立,则称R属于第三范式3NF,记作R3NFR\in 3NF
  • 3NF建立在2NF之上,要求所有的非主键列都必须直接依赖于主键,不包括任何传递依赖
  • R3NFR \in 3NF,则每一非主属性既不部分依赖于码也不传递依赖于码
  • R3NFR \in 3NF,则必有R2NFR \in 2NF
  • 采用投影分解法将一个2NF的关系分解为多个3NF关系,可以在一定程度上解决原2NF关系中存在的插入异常、删除异常、数据冗余度大、修改复杂等问题
  • 推论1:若R2NFR \in 2NF,且之多存在一个非主属性,则R3NFR \in 3NF
  • 推论2:任何二元关系模式R(A,B)必为3NF
  • 说明:
    • 部分FD和传递FD是用户及操作异常的重要根源
    • 3NF不存在非主属性对候选码的部分FD和传递FD
    • 3NF消去了大部分冗余及操作异常
    • 但并非所有的3NF都能完全消除冗余及操作异常
  • 3NF可能存在的问题:存在主属性对候选码的不良依赖

BC范式#

  • 定义:如果关系模式R(U,F)1NFR(U,F)\in 1NF,且对于所有的非平凡函数依赖X->Y,X必包含了R的一个码,则称R属于BC范式,记作RBCNFR\in BCNF

  • 定理:如果RBCNFR \in BCNF,则R3NFR \in 3NF

  • 性质:

    • 所有非主属性都完全依赖于候选码
    • 所有非主属性都不传递依赖于候选码
    • 所有主属性都完全依赖于不包含它的候选码;(主属性不依赖于主属性)
    • 所有主属性都不传递依赖于候选码
  • 推论:若一个关系达到了第三范式,并且它只有一个候选码,或它的每个候选码都是但属性,则该关系是BCNF

  • BCNF3NF2NF1NFBCNF\subseteq 3NF \subseteq 2NF \subseteq 1NF

  • 如果一个关系DB中所有关系模式都属于3NF,则已在很大程度上消除了插入异常和删除异常,但仍然可能存在主属性对候选键的部分依赖和传递依赖

  • 如果一个关系数据库中所有关系模式都属于BCNF,那么在函数依赖的范畴内,已经实现了模式的彻底分解,完全消除了产生插入异常和删除异常的根源,而且数据冗余也减少到极小程度

多值依赖#

  • 设R(U)是一个属性集U上的一个关系模式,X,Y,Z是U上的子集,并且Z=U-X-Y,多值依赖X->->Y成立,当且仅当

    • 对R的任一关系r,r在(X,Z)上的每个值对应一组Y的值
    • 这组值仅仅决定于X而于Z值无关
  • 多值依赖 VS 函数依赖

    • 函数依赖是多汁依赖的特里,若X->Y,则X->->Y
  • 区别

    • 函数依赖规定某些元组不能出现在关系中
    • 多值依赖要求某种形式的其它元组必须在关系中
    • 有效性与属性集的范围不同
      • X->Y的有效性仅决定于X,Y属性集上的值
      • X->->Y不仅涉及属性组X和Y,而且涉及U中其余属性Z
      • 若X->Y在R(U)上成立,则对于任何YYY' \subseteq Y,均有X->Y’成立
      • 多值依赖X->->Y若在R(U)上成立,不能断言对于任何YYY' \subseteqq Y有X->->Y’成立

4NF#

  • 定义:关系模式R<U,F>1NFR<U,F> \in 1NF,如果对于R的每个非平凡多值依赖X->->Y(yXy \subsetneq X),X都含有候选码,则R4NFR \in 4NF
  • 含义:不允许同一表内有多对多关系
  • 如果R4NFR \in 4NF,则RBCNFR \in BCNF

结论#

  • 3NF必定为2NF和1NF,反之不一定
  • 4NF必定为BCNF,BCNF一定为3NF,反之不一定
  • 3NF已在很大程度上控制了数据容易、很大程度上消去了插入和删除操作异常;但3NF分解仍不够彻底(可能存在主属性对候选码的部分fd和传递fd)
  • 在fd范围内,BCNF下已完全消去了插入删除异常
  • 4NF是多值依赖范畴内最高程度的规范化
  • 范式并非越高约好。理论上数据库涉及一般硬规范到3NF,但实际应用中为减少连接运算,提高查询效率,不一定都达到3NF
  • 适可而止(垃圾,连接运算)
  • 分解不唯一

数据依赖的公理系统#

  • 逻辑蕴含:对于关系模式R<U,F>,其任何一个关系r,若函数依赖X->Y都成立(即r中任意两元组s,t,若t[X]=s[X],则t[Y]=s[Y]),则称函数依赖集F逻辑蕴含X->Y,或X->Y从F推导出来的,或X->Y逻辑蕴含于F
  • 在关系模式R(U,F)中为F所逻辑蕴含的函数依赖的全体叫做F的闭包,记作F+
  • Armstrong公里的内容
    • 设有关系模式R(U,F),U为属性全集,F是U上的函数依赖集,X,Y,ZUX,Y,Z \subseteq U。则有
    • 自反律:若YXUY \subseteq X \subseteq U,则X->Y为F所蕴含(给出平凡的函数依赖)
    • 增广律:若X->Y为F所蕴含,则ZUZ \subseteq U,则XZ->YZ为F所蕴含
    • 传递律:若X->Y及Y->Z为F所蕴含,则X->Z为F所蕴含
  • Armstrong公理的推论
    • 合成规则:若X->Y,X->Z,则X->YZ
    • 分解规则:若X->YZ,则X->Y,X->Z
    • 伪传递规则:若X->Y,YW->Z,则XW->Z
  • 引理:如果Ai是关系模式R的属性,则X->A1…AN的充要条件是X->Ai均成立
  • 属性闭包:设有关系模式R(U,F),U={A1,…,An},XUX \subseteq U,F是U上的一个函数依赖集,则称所有用Armstrong公理从F推导处的函数依赖X->Ai中所有Ai的属性集合为属性集X关于F的闭包,记XF+X_{F^+}
  • 引理:函数依赖X->Y能由F根据Armstrong公理推导出来的充要条件是YXF+Y \subseteq X_{F^+}
  • 由引理可知道,判断X->Y是否能由F根据Armstrong公理导出,可转化为:求XF+X_{F^+},判定YXF+Y \subseteq X_{F^+}
  • 计算属性闭包的算法
    • 输入X,F,输出XF+X_{F^+}
    • 方法:
      • X(0)=ϕ\phi,X(1)=X
      • 如果X(0)!=X(1),置X(0)=X(1),否则转4
      • 对于F中的每个函数依赖Y->Z,若YX(0)Y \subseteq X(0),置X(1)=X(1)ZX(1)=X(1) \cup Z,即将Y的右部并入X(1)中,转(2)
      • 输出X(1),即为XF+X_{F^+}

函数依赖的等价和覆盖#

  • 等价:若F和G是R的两个函数依赖集,如果F+=G+F^+=G^+,则称F等价于G
  • 覆盖:若F和G是两个等价的函数依赖集F+=G+F^+=G^+,则称F覆盖G,同时G也覆盖F
  • 引理:设F和G是R的两个函数依赖集,则F和G等价的充分必要条件是FG+F \subseteq G^+GF+G \subseteq F^+

最小函数依赖集#

  • 若函数依赖F满足下列条件,则F为一个最小函数依赖集记作FmF_m
    • F中每个函数依赖的右部都是单属性
    • 对于F中的任一函数依赖X->A,F-{X->A}与F是不等价的(即F中不存在多余的依赖)
    • 对于F中的任一函数依赖X->A,不存在X的子集Z,使得F与(FX>A)Z>A(F-{X->A}) \cup {Z->A}等价(即左部无多余属性)
  • F的最小依赖集求解算法
    • 用分解规则将F中所有函数依赖的右部分解为单属性的函数依赖,去掉重复依赖
    • 去掉多余依赖:对每个依赖X->Y,令G=F-{X->Y},求XG+X_{G^+},若YXG+Y \subseteq X_{G^+},则X->Y为多余依赖,将其从F中去掉
    • 去掉依赖左部的多余属性:对每个左部为多属性的依赖,如果X->A,设X=B1…BM,逐一考察Bi,若A(XBi)F+A \in (X-B_i)_{F^+},则Bi是多余属性,用X-Bi代替X
    • 重复2,3,直到Fm不再改变
  • 注:F的最小函数依赖集不是唯一的,与计算顺序有关

模式的分解#

  • 设由关系模式R(U,F),称ρ=R1(U1,F1),...,Rn(Un,Fn)\rho = {R_1(U_1,F_1),...,R_n(U_n,F_n)}为R的一个分解
    • U=U1U2...UnU=U_1 \cup U2 \cup ... \cup U_n
    • UiU_iUjU_j可以相交,但不允许UiUjU_i \subseteq U_j
    • FiF_i是F在UiU_i上的投影(也可记作ΠRi(F)\Pi R_i (F)
  • 函数依赖集合XYXYF+&XYUi{X\rightarrow Y|X \rightarrow Y \in F^+ \& XY \subseteq U_i}的一个覆盖FiF_i称为F在属性集$$U-i$上的投影
  • 分解的目标
    • 达到更高级范式
    • 分解后数据可以还原
    • 分解后属性间的依赖关系保持不变

分解的正确性标准#

  • 无损连接性:分解所得到的各个关系模式经过自然链接可以还原成被分解的关系模式,既不增加原来没有的元组也不丢失原有的元组
  • 依赖保持性:分解所得到的哥哥关系模式上的函数依赖的集合与被分解关系模式原油的函数依赖集等价,没有被丢失的现象

分解的无损连接性和保持函数依赖性#

  • 任何关系模式R(U,F),ρ=R1,...,Rn\rho={R_1,...,R_n}是R的一个分解.若对R的任意关系r都有 ρ=ΠR1(r)ΠR2(r)...ΠRn(r)\rho = \Pi _{R_1}(r) ⋈ \Pi _{R_2}(r) ... ⋈ \Pi _{R_n}(r) 则称分解ρ\rho是一个无损分解
  • 即:无损分解可通过自然连接运算还原
  • 定义:任给定R(U,F),ρ=R1,...,Rn\rho={R_1,...,R_n}是R的一个分解,若 FΠR1(F1)ΠR2(F2)...ΠRn(Fn)F \leftrightarrow \Pi _{R_1}(F_1) \cup \Pi _{R_2}(F_2)\cup ... \cup \Pi _{R_n}(F_n) ,则称ρ\rho具有函数依赖保持性

无损连接性#

  • 算法:判定一个分解的无损连接性
    • 输入:R(A1,...,An),F,ρ={R1,...,Rk},F={FD1,...,FDρ}R(A_1,...,A_n),F,\rho=\{R_1,...,R_k\},F=\{FD_1,...,FD_{\rho}\},设FDiFD_iXiAiX_i \rightarrow A_i
    • 输出:分解ρ\rho是否具有无损连接性
    • 步骤:
      • 建立k*n的矩阵S,列j对应属性Aj,行i对应分解中的一个关系模式Ri 若属性Aj属于Ui,啧在j列i行出填写aj,否则填写bij
      • 逐个检查F中的每个函数依赖,利用fd数据间的等值关系,修改表中元素
      • 如果S中存在一行全为a类符号,啧ρ\rho具有无损连接性,否则不具有
  • 判断分解无损连接性的简单算法
    • 定理:设R(U,F),ρ=R1,R2\rho={R_1,R_2}是R的一个分解,F是R上的函数依赖集,ρ\rho具有无损连接性的充要条件是 (R1R2)(R1R2)F+or(R1R2)(R2R1)F+(R_1 \cap R_2) \rightarrow (R_1-R_2) \in F^+ \quad or \quad (R_1 \cap R_2 ) \rightarrow (R_2 - R_1) \in F^+

依赖保持性#

  • 设R(U,F),ρ={R1(U1,F1),...,Rk(Uk,Fk)}\rho=\{R_1(U_1,F_1),...,R_k(U_k,F_k)\}是R的一个分解,若F+=(F1...Fk)+F^+=(F_1 \cap ... \cap F_k)^+,则称ρ\rho具有函数依赖保持性

模式分解算法#

  • 要求分解保持函数依赖,模式分离总可以达到3NF, 不一定能达到BCNF

  • 要求分解既保持函数依赖又具有无损连接性,可以达到3NF,不一定能达到BCNF

  • 要求分解具有无损连接性,一定可以达到4NF

  • 算法(合成法)达到3NF且保持函数依赖的分解算法

    • 输入:给定关系模式R<U,F>
    • 输出:ρ={R1,...,Rk},Ri3NF,i=1,...,k\rho=\{R_1,...,R_k\},R_i \in 3NF, i=1,...,k
    • 步骤:
      • 求R的最小函数依赖集F’
      • 找出不在F’中出现的属性U0U_0,将他们构成一个关系模式R0<U0,F0>R_0<U_0,F_0>,并从U中去掉它们(剩余属性仍记为U)
      • 若有X->A,且AX=U,则ρ={R}\rho=\{R\},算法终止
      • 否则,对于F’中的每个X->A,构成一个关系模式XA.如果F’中有(左部相同)A->A1,X->A2,…,X->An,则可以用XA1…An代替掉n个模式XA1,…,XAn,Ui={XA1...An}U_i=\{XA_1...A_n\};如果发现某个UiUjU_i \subseteq U_j,则应将UiU_i去掉
      • ρ={R1<U1,F1>,...,Rk<Uk,Fk>}R0<U0,F0>\rho = \{R_1<U_1,F_1>,...,R_k<U_k,F_k>\} \cup R_0<U_0,F_0>
  • 算法:达到3NF既保持函数依赖又无损连接的分解

    • ρ={R1<U1,F1>,...,Rk<Uk,Fk>}\rho=\{R_1<U_1,F_1>,...,R_k<U_k,F_k>\}是R<U,F>的一个保持函数依赖的3NF分解(由上面一个算法获得)
    • 设X为R<U,F>的码,
      • 若有某个Ui,XUiU_i, X \subseteq U_i,则ρ\rho即为所求
      • 否则令τ=ρ{R<X,Fx>}\tau=\rho \cup \{R^*<X,F_x>\},τ\tau即为所求
      • 如果发现某个UiXU_i \subseteq X,则应将UiU_i去掉

第七章 数据库设计#

数据库设计的基本任务#

  • 概述
    • 数据库设计是指对于一个给定的应用环境,构造优化的数据库模式,建立数据库及其应用系统,使之能够有效的存储和管理数据,满足用户的应用需求(包括信息要求和处理要求)
    • 数据库设计通常使在已有硬件和OS平台上,利用一个通用的DBMS来建立能够实现系统目标的数据库
  • 数据库设计的内容
    • 数据库的结构设计(静态)
      • 根据给定的应用环境,进行数据库的模式/子模式的设计
      • 包括数据库的概念设计、逻辑设计和物理设计
      • 数据库模式是各个应用程序共享的结构,是静态的、稳定的,一经形成后通常情况下是不容易改变的。
    • 数据库的行为设计(动态)
      • 确定数据库用户的行为和动作。而在数据库系统中,用户的行为和动作指用户对数据库的操作,这些要通过应用程序来实现,所以数据库的行为设计就是应用程序的设计。
      • 用户的行为总是使数据库的内容发生变化,所以行为设计是动态的,行为设计又被称为动态模型设计。
  • 数据库设计的特点
    • 结构设计与行为设计相结合
      • 面向数据的设计方法(以信息需求为主)
      • 面向过程的设计方法(以处理需求为主)
    • 分步进行
      • 数据库设计分为多个阶段
      • 前一阶段的设计结果作为后一阶段设计的依据
      • 后一阶段也可向前面的设计阶段反馈其要求
    • 反复性
    • 多解
  • 数据库设计方法
    1. 直观设计(手工凑)
    2. 规范设计法
    3. 计算机辅助设计法
    4. 自动化设计法
  • 数据库设计的步骤
    • 需求分析
    • 概念结构设计
    • 逻辑结构设计
    • 物理设计
    • 数据库实施
    • 数据库运行与维护
      • 需求分析和概念设计独立于任何数据库管理系统
      • 逻辑设计和物理设计与选用的DBMS密切相关

需求分析#

  • 需求分析的任务
    • 调查的重点
      • 信息要求
      • 处理要求
      • 安全与完整性要求
  • 需求分析的方法
    • 自顶向下的分析方法,简称SA方法,是最简单使用的方法
      • 从最上层的系统组织机构入手
      • 采用逐层分解的方式分解系统
      • 用数据流图Data Flow Diagram, DFD 和 数据字典Data Dictionary, DD 描述系统
  • 需求分析过程
    1. 首先把任何一个系统都抽象为需求分析系统抽象
    2. 分解处理功能和数据:
      • 将处理功能和具体内容分解为若干子功能
      • 处理功能逐步分解同时,逐级分解所用数据,形成若干层次的数据流图DFD
      • 表达方法:
        • 处理逻辑:用判定表或判定树来描述
        • 数据:用数据字典DD描述
    3. 将分析结果再次提交给用户,获得认可
  • 数据字典
    • 数据字典是对系统中数据的详细描述,是各类数据结构和属性的清单。与数据流图互为注释
    • 数据字典贯穿于数据库需求分析直到数据库运行的全过程,在不同阶段其内容和用途各有区别
    • 在需求分析阶段,包含以下五部分
      1. 数据项:不可再分的数据单位
        • 数据项是数据的最小单位
        • 包括{数据项名、含义说明、别名、类型、长度、取值范围、与其它数据项的关系等}。
        • 其中,取值范围、与其它数据项的关系:定义了完整性约束条件,是设计数据检验共嗯那个的依据。
      2. 数据结构:反应了数据之间的组合关系
        • 一个数据结构可以由若干个数据项组成,也可以由若干个数据项和数据结构混合组成
        • 内容包括:{数据结构名、含义说明,组成:{数据项或数据结构}}
      3. 数据流:表示某一处理过程中数据在系统内传输的路径
        • 内容包括:{数据流名、说明、流出过程、流入过程、组成:{数据项或数据结构},平均流量、高峰值}
        • 其中,流出过程说明该数据流由什么过程而来,流入过程说明该数据流到什么过程
      4. 数据存储:数据的存放场所
        • 也是数据流的来源和去向之一。
        • 包括:{数据存储名,说明,输入数据流,输出数据流,组成:{数据项或数据结构},数据量,存取频度,存取方式。存取方法:批处理/联机处理;检索/更新}
      5. 处理过程:具体处理逻辑
        • 处理逻辑通常用判定表或判定树来描述
        • 处理过程包括{处理过程名,说明,输入:{数据流},输出:{数据流},处理:{简要说明}}
        • 其中,简要说明:说明处理过程的功能及处理要求
        • 功能是指该处理过程用来做什么(不是怎么做),处理要求指该处理频度要求,如单位时间里处理多少事务、多少数据量、响应时间要求等,这些处理要求是后面物理设计的输入及性能评价的标准。
  • 数据流图DFD数据流图DFD

概念结构设计#

概念设计就是将需求分析得到的用户需求抽象为信息结构,即概念模型

  • 描述工具:E-R图

  • 特征:独立于硬件,也独立于软件

  • E-R图

    • E-R数据模型提供了实体、属性和联系三个主要的抽象概念
    • E-R数据模式:用E-R数据模型对一个系统的模拟
    • E-R图:
      • 矩形:实体集
      • 椭圆:属性
      • 菱形:联系集
      • 线段:将属性连接到实体集或将实体集联系到联系集,无向边上标明联系的类型(1:1,1,m)
    • 实体与属性
      • 实体:客观存在并可相互区分的事物;一类实体具有相同或相似的特性
      • 属性:实体所具有的某一方面的特性
        • 单一属性和复合属性
          • 在关系模型中,复合属性一定要转化为单一属性(1NF)
        • 单值属性和多值属性
          • 关系模型中,多值属性一定要转化为单值属性(1NF)
        • 可空值属性和非空值属性
        • 导出属性:由其它属性计算而得
  • 概念模型设计的方法和步骤

    1. 概念结构设计的方法
      1. 自顶向下:先定义全局框架,再逐步细化 —> 常用需求分析
      2. 自底向上:先定义局部E-R图,然后将它们集成,得到全局E-R模型 —> 常设计概念结构
      3. 逐步扩张:先定义核心概念E-R模型,然后以滚雪球的方式逐步生成其它概念结构E-R模型
      4. 混合策略:自顶向下和自底向上结合的方法
    2. 步骤
      1. 数据抽象和局部设计:利用抽象机制对需求分析阶段收集的数据进行分类、组织形成实体、实体的属性,标识实体的码,确定实体之间的联系类型,设计分E-R图
        • 设计分E-R图:选择局部应用,确定范围原则:
          • 相对独立
          • 内部联系较紧密
          • 与外部联系相对较少
        • 逐步设计分E-R图:利用抽象机制形成实体、属性,确定联系等。
        • 划分实体和属性的准则:
          • 实体具有描述信息,而属性没有。属性必须是不可分的,不能包含其它属性。可再分者为实体。
          • 联系只能发生在实体之间。
          • ~一般情况下,凡能作为属性对待的,应尽量作为属性,以简化E-R图的处理
      2. 集成局部设计,生成全局概念结构
        • 集成的方式:
          • 多元集成法:一次性将多个局部E-R图合并为一个全局E-R图(复杂)
          • 二元集成法:首先集成两个重要的局部视图,以后用累加的方法逐步将一个新的视图集成进来。
        • 无论使用哪一种方法,集成均分为两个步骤:
          1. 合并:消除局部E-R图之间的冲突,生成初步E-R图
          2. 优化:消除不必要的冗余,生成基本E-R图
  • 全局ER模型设计

    • E-R图中的冲突有三种:属性冲突、命名冲突和结构冲突
    • 属性冲突:
      • 属性值冲突:类型、取值范围或取值集合不同
    • 命名冲突:
      • 命名不一致可能发生在实体名、属性名或联系名之间,其中属性的命名冲突更常见
    • 结构冲突:同一对象在不同应用中有不同的抽象,可能为实体,也可能为属性。
      • 解决方法:统一抽象级别
      • 同一实体在不同应用中属性组成不同,可能是属性个数或属性次序不同。解决办法:取局部E-R图中的同名实体属性的并集,然后再适当调整属性的次序
      • 同一联系在不同应用中呈现不同的类型。解决办法:根据应用予以对实体联系的类型进行综合调整。
    • 消除不必要的冗余,生成基本E-R图
      • 冗余包括冗余的数据和冗余的联系
        • 冗余的数据是指可由基本的数据导出的数据
        • 冗余的联系是由其它的联系导出的联系
      • 消除了冗余的初步E-R图称为基本E-R图
      • 通常采用分析的方法消除冗余。数据字典是分析冗余数据的依据,还可以通过是数据流图分析出冗余的联系。

逻辑结构设计#

  • 逻辑设计的任务
    • 将概念结构转换成特定的DBMS所支持的数据模型
    • 进入“实现设计”阶段,需考虑具体DBMS性能,具体数据模型特点
    • 关系数据库的逻辑设计问题:E-R图如何向关系模型进行转换
  • E-R图向关系模式的转换
    1. 转换原则
      1. 一个实体型转化为一个关系模式
        • 关系属性=实体的属性
        • 关系的码=实体的码
      2. 联系转换方式1:
        1. 联系为1:1,联系实体可以消失,每个实体的键都是关系的候选键
        2. 联系为1:n,联系实体可消化到”m”方中去,n端实体的键是关系的键
        3. 联系为n或多元联系,联系实体转化为一个关系,各实体键的组合是关系的键
      3. 联系的转换方式2:一个联系转换为一个关系模式,与该联系相连的各实体的键以及联系的属性均转换为该关系的属性
        1. 联系为1:1,则每个实体键都是关系的候选键
        2. 联系为1,则n端实体的键是关系的键
        3. 联系为n,则各实体键的组合是关系的键
      4. 具有相同码的关系模式可以合并
  • 数据模型的优化
    • 数据库逻辑设计的结果不是唯一的,得到初步数据模型后,还应适当修改、调整数据模型的结构,以进一步提高数据库应用系统的性能
    • 关系数据模型的优化通常以规范化理论为指导
    • 优化方法为:
      • 确定数据依赖
      • 消除冗余联系
      • 确定所属范式级别
      • 检验生成的模式是否合适应用环境实施规范化处理,是否需要对某些模式进行合并或分解
    • 并不是规范化程度越高的关系就越优
    • 优化:
      • 确定函数依赖
      • 得到函数依赖集合FL
      • 求FL的最小覆盖GL,差集为D=FL-GL
      • 逐一考察D中的函数依赖,确定是否是冗余的联系,如果是,就把它去掉
    • 对关系模式进行必要分解,提高数据操作效率和存储空间利用率
      • 水平分解:把关系的元组分为若干子集合,定义每个子集合为一个子关系
        • 经常进行大量数据的分类条件查询的关系,可进行水平分解,可以减少应用系统每次查询需要访问的记录数,提高查询性能
        • 适用范围:20%的常用数据分解出来作为子关系 & 并发事务经常存取不相交的数据:分解为每个事务存取的数据对应一个关系
      • 垂直分解:把关系模式的属性分解为若干字集合,形成若干子关系模式
        • 原则:把经常一起使用的属性分解出来,形成一个子关系模式
        • 有点:提高某些事务的效率
        • 缺点:由可能使另一些事务不得不执行连接操作,降低了效率
        • 衡量标准:分解后的总效率是否得到提高?还要保证分解后的关系具有无损链接性和函数依赖保持性
  • 设计用户子模式

物理结构设计#

  • 对于给定的逻辑数据模型,选取一个最适合应用环境的物理结构的过程,称为数据库物理设计
  • 任务:以逻辑设计的结果为输入,结合具体DBMS的特点与存储设备特性进行设计,选定数据库在物理设备上的存储结构和存取方法
  • 两步:
    • 确定物理结构:在关系数据库中主要指存取方法和存储结构
    • 评价物理结构:评价的重点是时间和空间效率、维护代价和各种用户 要求进行权衡
  • 数据库物理设计的内容和方法
    • 准备工作:分析所需要的参数
      • 数据查询事务:关系、查询条件所涉及的属性、连接条件所涉及的属性、查询投影属性
      • 数据更新事务:关系、更新条件所涉及所有属性,每个事务的频率和性能要求
    • 关系模式存取方法选择
      • 索引:经典存取方法 - B+树索引
      • 聚簇Cluster
      • HASH方法

关系模式存取方法#

索引#

  • 索引是根据某些属性的值建立的值与对应记录的存储位置间的映射关系表,它可以提供对数据的快速访问
  • 选择索引存取方法的一般规则:
    • 如果一个(或一组)属性经常在查询条件中出现,则考虑在这个(或这组)属性上建立索引(或组合索引)
    • 如果一个属性经常作为最大值和最小值等聚集函数的参数,则考虑在这个属性上建立索引
    • 如果一个(或一组)属性经常在连接操作的连接条件中出现,则考虑在这个(或这组)属性上建立索引
  • 关系上定义的索引数过多会带来较多的额外开销
    • 维护索引的开销
    • 查找索引的开销

聚簇#

  • 聚簇:为提高某个属性(或属性组)的查询速度,把这个或这些属性(称为聚簇码)上具有相同值的元组集中存放在连续的物理块称为聚簇。
  • 聚簇有两个作用:
    • 聚簇码相同的元组集中在一起,因而聚簇值不必在每个元组中重复,只要在一组中存储1次即可,因此可以节省存储空间
    • 聚簇功能可以大大提高按聚簇进行查询的效率
  • 设计候选聚簇:
    • 对经常在一起进行连接操作的关系可以建立聚簇
    • 如果一个关系的一组属性经常出现在相等比较条件中,则该单个关系可以建立聚簇
    • 如果一个关系的一个(或一组)属性上的值重复率很高,则此单个关系可建立聚簇,即对应每个聚簇码值的平均组数不太少。太少则聚簇效果不明显
  • 优化聚簇设计
    • 从聚簇中删除经常进行全表扫描的关系
    • 从聚簇中删除更新操作远多于连接操作的关系
    • 不同的聚簇中可能包含相同的关系,一个关系可以在某一个聚簇中,但不能同时加入多个聚簇
    • 从这多个聚簇方案(包括不建立聚簇)中选择一个较优的,即在这个聚簇上运行各种事务的总代价最小
  • 适用范围:
    • 既适用于单个关系独立聚簇,也适用于多个关系组合聚簇
    • 当通过聚簇码进行访问或连接是该关系的主要应用,与聚簇码无关的其它访问很少或者是次要的时候,可以使用聚簇
      • 尤其是当SQL语句中包含有聚簇码有关的order by, group by, union, distinct等子句或短语时,使用聚簇特别有利,可以省去对结果集进行排序操作。
  • 局限性:
    • 聚簇只能提高某些特定应用的性能
    • 建立与维护聚簇的开销很大
      • 对已有关系建立聚簇,将导致关系中元组移动其物理存储位置,并使此关系上原有的索引无效,必须重建
      • 当一个元组的聚簇码改变时,该元组的存储位置也要做相应移动

HASH存取#

  • 规则:
    • 当一个关系满足下面两个条件时候,可以选择hash存取方法:
      • 该关系的属性主要出现在等值连接条件中或主要出现在相等比较选择条件中
      • 关系的大小可以预知,而且不变
      • 或 该关系大小动态改变,但所选用的DBMS提供了动态hash存取方法

确定数据库存储结构#

  • 确定数据的存放位置
    • 为了提高系统性能,应该根据应用情况将数据的易变部分、稳定部分、经常存取部分和存取频率较低部分分开存放
  • 确定系统配置

评价物理结构#

  • 存储空间
  • 存取时间
  • 维护代价

第八章 关系数据库引擎基础#

数据库存储#

数据存储概述#

面向内存 VS 面向磁盘

  • 数据库存储管理目标
    • 允许DBMS管理可超过内存大小的数据库
    • 由于读写磁盘代价很高,存储管理要能够避免大的延时和性能下降
    • 由于磁盘随机访问比顺序访问慢很多,DBMS希望能最大化顺序访问
  • 磁盘块访问的优化
    • 缓冲
    • 预读取
    • 调度
    • 文件组织
    • 非易失写缓冲区
    • 日志磁盘
  • 面向磁盘的DBMS
    • 特征:
      • 数据库文件存储在磁盘上,数据被组织成”页“,第一页是目录页
      • 缓冲池管理和磁盘的内存间数据交换:磁盘I/O对性能影响巨大

数据库存储结构#

  • 文件存储
    • DBMS通常按一定的自有、专有格式组织并将数据库存储在一个或多个磁盘文件中。OS并不知晓这些文件的组织形式和内容。
    • DBMS的存储管理器:负责数据库文件的管理,将文件组织为”页“的集合,追踪页面数据的读写操作,追踪可用的存储空间
  • 页设计
    • 数据库的页是一个固定大小的数据块
    • 页可以容纳
      • 不同类型数据:元组、元数据、索引、日志记录等
      • 数据一般不能混合存放,即一个页只存放一类信息(比如元组)。
      • 一些DBMS要求页面是“自包含”的
    • 页ID:每个页具备唯一ID
      • 当数据库只有单文件时,页面ID可以就是文件中的偏移地址
      • 当有多个文件时,大部分DBMS会有个间接层来映射页面ID到文件的路径和偏移地址,系统访问页面号时,存储管理器将其转换为文件路径和偏移地址
  • 页的堆文件组织方式
    • 关系是记录的集合,这些记录在数据库文件中可以有3中组织方式
      • 堆文件组织
      • 顺序文件组织
      • 散列文件组织
    • Heap文件是一个无序的page集合,其中的元组可按随机顺序存放
      • 支持page的创建、读、写和删除操作
      • 支持遍历所有pages的操作
    • 堆文件的2种表示方式
      • 链表
        • 以链表的形式将文件中的空闲页和数据页分别勾连起来
        • 堆文件头部设立一个header page,并存放俩个指针,分别指向
          • 空页列表头部
          • 数据页列表头部
        • 每个page均记录当前空闲的空槽slot
      • 页目录
        • 维护一种特殊的页面(页目录),用于记录所有的数据页的存放位置
        • 该目录页同时记录每个页面的空槽信息
        • 页目录将页面的状态信息集中u村南方在一起,可提高查找特定页面的速度
        • DBMS必须保持目录页于所有页的<page_id, relative_offset, free_space_size>同步
  • 页的组织结构
    • 页头:包含有关页内容的元数据信息
      • 页大小 校验 DBMS版本 事务可见性 压缩信息
      • 有些系统要求页面是自包含的
    • 数据区:存放数据的区域,其存放方式:
      • 面向元组型
        • strawman idea
          • 记录页内的元组数,类似数组的方式进行存储
          • 每次添加的元组放在已有元组的后面
          • 存在问题:
            • 删除元组时会产生碎片
            • 变长元组可能产生其它更多问题,比如元组的查询开销
        • 槽页:slot数组将槽位映射到元组开始的位置的偏移量
          • Header记录已经占用的槽位 和 最后一次使用的槽的起始位置偏移
          • 元组:在页内倒序存放
          • 元组在内部的唯一标识符:page_id+offset/flot,页可包含文件位置信息
          • 定长和变长元组都可处理
        • 元组设计
          • 一个元组在页中本质上是一个“字节序列”
          • DBMS负责将这些字节解释为各个属性的类型和值
          • 记录包括:记录头、记录数据
          • tuple header:每个元组有一个前缀为header的元数据
            • 页中无需存放关系模式信息,专门的catalog page可有效减少重复信息
          • tuple data:实际数据,基本上按属性顺序存放
          • 定长记录:全部由定长字段组成
            • 定长记录的插入和删除容易实现
            • 注意内存对齐问题
          • 变长记录:允许记录中存在一个或多个变长字段。变长字段在记录中的偏移位置不确定
            • 将所有定长字段放在边长字段之前,记录头增加:记录长度+非第一个变长字段的offset
            • 保持记录定长,变长部分放在另一个溢出页
          • 物理上非规范化元组设计:(预连接)将相关的元组存放在一个页或相邻页中
            • 可以有效减少相应查询的I/O次数
            • 也可能带来额外的数据维护开销
      • 日志结构型
        • DBMS不存储元组,值存储日志记录
        • 系统添加日志记录来反应数据库更新的结果
          • 插入:存放整个元组
          • 删除:标记该元组被删除
          • 更新:记录被修改的属性的变化
        • 当需要读取日志记录,DBMS可以反向扫描日志,重新创建元组,还可以“回滚”
        • 日志可定期压缩(通过删除不必要的记录来合并日志文件)
        • 日志文件组织
          • 不同数据通常可能在不同的page,如果将更新信息写到数据页,需要访问多个page
          • 将数据更新信息写道一个或者连续页效率更高
          • 可建立“日志索引”,方便查找相关的日志记录
          • 定期压缩日志,取出不必要的记录

系统目录#

  • DBMS将数据库的元数据(描述信息)存放在内部的目录(数据字典)中
    • 表、列、索引、视图
    • 用户、权限
    • 数据的统计信息
    • 存储过程、触发器等

存储模型#

  • 联机事务处理OLTP —> 行存储
  • 联机分析处理OLAP —> 列存储
  • 复合事务分析处理HTAP 为了适应OLTP或OLAP不同的工作负载,DBMS可采用不同方式进行元组存储
  • NSM 行存储
    • 行存储模型非常适合OLTP
    • 单个元组读所有属性连续分布在一个page中,查询往往涉及单个实体(工作量较烧),并能够适应较为繁重的“更新”工作量
  • DSM 列存储
    • DBMS将单个属性的值连续组织在一个page中,按列存储
    • 更是个OLAP ,可以很好的适应大数据量、复杂查询语义、高负载查询
      • 如何进行“元组标识”
      • 选择1:固定长度偏移,对某个属性每个值具备相同宽度
      • 元组ID嵌入,每个值于其元组ID一起存放
    • 优点:
      • 由于只读取需要的数据,减少了对无用数据的I/O
      • 更便捷的查询处理
      • 有利于数据压缩的实现
    • 缺点:
      • 数据被拆分,有些查询需要缝合,影响查询速度,也同时影响增删改效率

缓冲池#

工作原理#

  • 执行引擎在语句处理过程中需要使用某个数据页时,会像缓冲池提出请求
  • 缓冲池管理器负责将该页面从磁盘读入内存,并向执行引擎提供该页面在内存中的指针
  • 当执行引擎操作那部分内存时,缓冲池管理器必须确保该页面始终在内存区域中

本节重点:DBMS如何管理数据在磁盘和缓存之间的交互,缩小CPU速度与磁盘速度之间的鸿沟

  • 缓冲池的作用
    • 减少磁盘I/O,提升页面读写效率
      • 读操作时,若所需页面已加载到缓冲池,就不需要从磁盘读了
      • 写操作时,如果多次修改了同一页面,只需要写一次磁盘
    • 缓冲池管理目标:尽可能减少磁盘I/O带来的延时

缓冲池结构#

  • 缓冲池是在DBMS内部分配的一大片内存区域,用于存储从磁盘获取的页面

  • 用于缓存页面的内存空间被粗制为一个数组,其中每个数组向被称为一个帧,一个真正好能放置一个页面

  • 页表是缓冲池管理器用于维护缓冲池元数据的数据结构

  • 缓冲池页表:

    • 页表:是一个内存散列表,用于等级当前已加载到缓冲池中的页面的信息
  • 页表为缓冲池中每个页面维护以下信息:

    • 位置信息:页面在缓冲池中对应帧的位置
    • 脏标志:页面被修改过的标志。如果一个页面被设置了脏标志,则缓冲池管理器必须确保将其写回磁盘
    • 引用计数:当前正在访问该页的线程数量。如果某页的引用计数大于零,则不允许淘汰该页(pin)

缓冲池管理策略#

  • 锁lock vs 闩 latch

  • 锁和闩分别用于DBMS中两个级别的并发控制

  • 锁:事务级

    • 保护的是数据库中的逻辑对象,如表、元组等
    • 持锁时间较长,一般直到事务提交才释放
    • 上锁期间对上锁对象的修改可以回滚
  • 闩:(进程)线程级

    • 保护的是DBMS中多线程/进程共享的内部数据结构(临界资源),如帧
    • 一般用OS的同步机制(如信号量)实现,加闩时间短,操作完立刻释放
    • 加闩期间的修改无需考虑回滚
  • 分配策略:关于缓冲池中的内存空间如何分配的问题,缓冲池管理器采取2中策略:

    • 全局策略
    • 局部策略

缓冲池替换算法#

  • LRU算法:为每个页面维护其最后一次被访问的时间戳,需要淘汰页面时,DBMS总是选择淘汰时间戳最早的页面

    • 把入缓冲池的页放在LRU的头部,作为最近访问的元素,从而最晚被淘汰。为了减少数据移动,一般用链表实现
      • 页已经在缓冲池里:只把页面移动至LRU头部的动作,没有页面被淘汰
      • 页不在缓冲池里:除了放入LRU头部的动作,还要淘汰LRU尾部页的动作
  • CLOCL算法:页称为近似LRU算法,为每个页面维护一个引用位,当某个页面被访问时,就将其引用位置为1。需要淘汰页面时候,循环扫描缓冲池中的页面检查各页面的引用位是否为1.如果是,则将引用位置为0并移动指针到下一个页面;否则淘汰当前页。

  • LRU算法和CLOCK算法的缺点:

    • 预读失效:由于预读,提前把页放入了缓冲池,但最终DBMS并没有从页中读取数据
    • 顺序洪泛:因一次顺序扫描需要将表的所有页面读入缓存,导致缓存污染
  • LRU-K算法

    • 核心思想:将淘汰页面时锁考察的最近访问次数由1提升为K
    • 维护两个队列:
      • 历史队列:保存着新进入内存的页面及其访问次数,还有每一次的访问时间,当一个页面的访问次数达到K此,则将该页面保存至缓存队列;若历史队列满了,则根据一定的淘汰策略淘汰
      • 缓存队列:保存着已经访问过K此的页面,当该队列满了之后,则根据LRU策略淘汰倒数第K次访问距离现在最久的那个页面
  • 要优化预读失效

    • 让预读失败的页,停留在缓冲池LRU里时间尽可能短
    • 让真正被读取的页,才挪到缓冲池LRU的头部
  • 具体方法:

    • 将LRU分为新生代、老生代
    • 新老生代首尾相连
    • 新页加入缓冲池时,只加入到老生代头部
    • 若数据真正被读取(预读成功),才会加入新生代头部
  • 脏页的处理:

    • 快速:优先淘汰非脏的页(可能留着用不到的脏页)
    • 慢速:写回磁盘再淘汰
    • 后台写:定时写

缓冲池的优化#

  • 多缓冲池
    • DBMS维护多个用于不同目的的缓冲池
    • 可以是多个缓冲池实力,每个数据库使用一个缓冲池每种页面类型使用一个缓冲池
    • 各缓冲池可以采用量身定制的管理策略
  • 预取
    • 再处理第一组页面时,DBMS优先将第二组页面读取到缓冲池中
    • 顺序访问的时候使用该方法
  • 扫描共享:某些查询结果可以公用
    • 将多个查询附加到一个游标上,查询游标可以重用从磁盘读入的数据或操作符的计算结果,减少重复访问的次数
  • 缓冲池旁路
    • 为避免开销,顺序扫描操作符不会将获取的页存储再缓冲池中,而是使用正在运行的查询的本地内存
    • 如果操作符需要读取磁盘上连续的大量页序列,那么这种方法可以很好的工作
    • 缓冲池旁路页可以用于临时数据,入排序、连接

索引#

  • B+树性质

  • B+树是一种自评很的树型数据结构:它保持数据排列,允许在O(logn)O(logn)的复杂度内进行搜索、顺序访问、插入和删除

  • 二叉搜索树的泛化,一个节点可以有2个以上的子节点

  • 针对读写大数据快的系统进行优化

  • B+树只在叶子节点中存储值,。内部节点无data域,仅用于引导搜索过程,内节点每个节点能索引的范围更大更精确。B+树更是适合外部存储

  • B+树的内部节点结构(阶为M)

    • 对于每个形如<P1,K1,P2,K2,...,Pc1,Kc1,Pc><P_1,K_1,P_2,K_2,...,P_{c-1},K_{c-1},P_c>的内部节点,其中c<Mc<M,每一个PiP_i表示指向子树跟节点的指针,KiK_i表示关键字值
    • 内部节点的关键字由小到大排列
    • 对于一个位于PiP_i所指向的子树中的节点X而言,
      • 1<i<c1<i<c,均有Ki1<X<=KIK_{i-1}<X<=K_I
      • 当i=c时,X>Kc1X>K_c-1
      • 当i=1时,X<=K1X<=K_1
    • 每一个内部节点最多有M个指向子树的指针,即c最大取M
    • 根节点至少包含两个指向子树的节点指针,对于根节点而言,2<=c<=M2<=c<=M
    • 除了根节点之外的每个节点都包含最少ceil(M2)ceil(\frac{M}{2})个指向子树的指针,完全平衡树
    • 如果任意一个内部节点包含c个指向孩子节点的指针而且c<=Mc<=M,则该节点包含c-1的关键字
  • B+树的叶子节点结构(阶为N)

    • 对每一个形如<<K1,D1>,<K2,D2>,...,<KC1,DC1>,Pnext><<K_1,D_1>,<K_2,D_2>,...,<K_{C-1},D_{C-1}>,P_{next}>的叶子节点,其中c<=N,DiD_i是一个数据指针(指向磁盘上的值等于KiK_i的真是记录的指针,或者包含记录仪KiK_i的磁盘文件块),KiK_i是一个关键字,PnextP_{next}表示B+树中指向下一个叶子节点的指针
    • 对任意一个叶子节点,均有
      • K1<K2<...<KC1K_1<K_2<...<K_{C-1}
      • c<=N
    • 每一个叶子节点至少包含ceil(M2)ceil(\frac{M}{2})个值
    • 所有的叶子节点在同一层
    • 使用PnextP_{next}指针可以遍历所有的叶子节点,就和单链表一样,从而实现对磁盘上记录的有序访问
  • 选择条件

    • 如果查询提供了B+树搜索关键字的任何属性的值,DBMS就可以使用B+树索引
      • 全值匹配
      • 匹配最左前缀
      • 匹配列前缀
      • 匹配范围值
      • 只访问索引的查询
    • 索引的分类
      • 主键索引/唯一索引/普通索引/全文索引/组合索引
  • B+树插入操作

    • 若为空树,创建一个叶子节点,将记录插入其中,此叶子节点为根节点,插入操作结束
    • 针对叶子节点
      • 根据key值去欸的那个叶子几点L,将排序后的关键字插入此节点L
      • 如果空间充足(即节点L含有的关键字数目小于阶数m),则插入结束
      • 否则将节点L分裂为左右两个叶子节点LLL2L_2
        • 左叶子几点包含前m2\frac{m}{2}个记录
        • 右叶子节点包含剩下的记录
        • 将第m2+1\frac{m}{2}+1个记录的key进位到父节点中,并完成在父(内)节点的插入 (可能引起分裂递归)
  • B+树删除操作

    • 如果叶子节点中没有相应的key,则删除失败,否则执行
    • 如果跟节点除法找到该关键字所在节点L,删除该关键字
    • 如果节点L的关键字数目不少于M2\frac{M}{2},则删除完成,结束
    • 如果节点L仅有M21\frac{M}{2}-1个关键字数目,向兄弟节点借一个关键字(兄弟节点指与L有相同父节点的相邻节点)
    • 否则将节点L与兄弟节点合并,合并时需要删除父节点中的关键字(指向L或其兄弟节点,可能引起删除内节点的级联合并)
  • B+树的重复键

    • 附加记录ID作为键的一部分:每个元组的记录ID是唯一的,确保了所有键都是可识别的
    • 允许叶节点溢出至包含重复键的溢出节点
  • 索引适用场景

    • 如果一个(或一组)属性经常在查询条件中出现,则考虑在这个(或这组)属性上建立索引(或组合索引)
    • 如果一个属性经常作为最大值和最小值等聚集函数的参数,则考虑在这个属性上建立索引
    • 如果一个(或一组)属性经常在连接操作的连接条件中出现,则考虑在这个(或这组)属性上建立索引
  • 聚簇适用场景(第七章就有了)

第九章 关系查询处理及优化#

关系数据库系统的查询处理#

查询处理步骤#

  • 查询分析

  • 查询检查

  • 查询优化

  • 查询执行

  • 查询计划:

    • 操作算子以树的形式进行组织
    • 数据流从叶子节点流向根节点
    • 根节点的输出是查询的结果

查询处理模型#

处理模型定义系统如何执行一个查询计划,不同的任务负载对应不同的权衡结果

  • 迭代模型:每个查询计划的算子执行一个next函数

    • 也称作火山模型/流水线模型
    • 该计算模型将关系代数中的每一个操作抽象为一个operator,将整个SQL构建成一个operator树,查询树子顶向下的调用next()接口,数据则自底向上的被拉取处理
    • 每次调用next得到一个元组,或者一个空值标记
    • 算子通过循环调用它的子节点的next函数用于获取元组进行,当处理完成后再通过next函数获取下一个元组处理组进行处理,直到得到一个null
    • 获取磁盘数据代价太大,需要它在内存中做足够多的操作
    • 特点
      • 几乎所有的DBMS都采用该模型,允许元组流水线
      • 流水线的好处
        • 消除读和写临时关系的代价,从而减少查询计算代价
        • 流水线产生查询结果,边生成边输出给用户,提高相应时间。很容易控制输出,如limit操作
      • 有些算子会阻塞数据的流动,直到其子节点发送所有的元组,如join操作,子查询操作,排序操作
  • 物化模型

    • 算子一次性获取它所有的输入,当处理完成后再返回给它的父节点
    • 算子能物化其输出作为一整个结果
    • 为了避免下层算子返回的数据量过大,上层算子可以尽可能提供多的过滤条件.DBMS会将一些参数传递到操作符中,防止处理过多的数据
    • 输出可以是整个元组(NSM存储模式),或属性自己(DSM存储模式)
    • 特点:
      • 适合OLTP,一次处理少量数据
      • 相对火山模型,较少的函数调用,能减少不必要的执行、调度成本
      • 不适合OLAP,AP查询可能产生较大的中间结果
  • 向量/批量模型

    • 执行框架同火山模型
    • 不同之处是每次调用Next函数,返回的是一批batch元组而不是一个元组。操作符内部的循环每次也是一批一批的处理
    • 特点:
    • 介于火山模型和物化模型之间
    • 适用于OLAP
    • 允许用户适用向量化的SIMD指令处理批量元组
  • 查询树处理的方向

    • 自顶而下:从根节点开始不断的向子节点拉去数据,元组通过函数调用传递
    • 自底向上:从叶子系欸但开始获取数据不断的向父节点推送数据

数据存取#

  • 数据存取方法:访问存储在表中的数据的方法。并没有在关系代数中被定义

  • 顺序扫描

    • 对于表的每一个page
      • 加载到bufferpool中
      • 对bufferpool的page中符合条件的tuple依次进行处理
      • DBMS内部维持一个游标指向上次访问的page/slot
    • 优化
      • zone map:预先计算一个页中的属性统计值(最大值,最小值,平均值),并存入zonema品种,在顺序扫描中根据zonemap来决定是否读取该页
      • late materialization:延迟缝合元组,直到查询计划的上层才缝合
  • 索引扫描:通过索引来访问查询所需要的数据页

  • 多索引扫描(位图扫描)

    • 对每个索引进行扫描,获取哪些指向满足单个条件的元组ID(或元组指针)
    • 根据谓词求取这些元组ID集合的交集或并集
    • 根据剩余的谓词(没有索引)过滤这些元组
  • 连接操作典型实现方法

    • 嵌套循环方法
      • 对外层循环的每一个元组,检索内存循环中的每一个元组sc
      • 检查这连个元组在连接属性上是否先庚
      • 如果满足连接条件,则串接后作为结果输出,直到外层循环表中的元组处理完为止
    • 排序-合并方法
      • 适合连接的诸表已经排好序的情况
      • 如果已经有序,O(m+n)
      • 否则O(mlog(m)+nlog(n))
    • 索引连接方法
      • 在内关系上建立连接属性的索引(如果原来没有)
      • 对外关系中每个元组,由连接属性的值通过内关系的索引查找相应的内关系元组
      • 把这些内关系元组和外关系元组连接起来,循环执行上一条和本条语句,直到外关系的元组处理完为止
      • 若I/O开销为C,则总开销M+(m*C)
      • 如果两个关系上均由索引时,一般把元组较少的关系作外关系效果比较好
    • hash join方法
      • 把连接属性作为hash码,用同一个hash函数把R和S中的元组散列到同一个hash文件中
      • 步骤
        • 划分阶段
        • 试探阶段,也称为连接阶段
      • 设内关系被划分成X个散列桶,创建散列表的成本(m)+散列函数的计算开销n+(m/X)n创建散列表的成本(m)+散列函数的计算开销*n+(m/X)*n
  • 连接算法的选择

    • 空闲内存:内存不够则无法适用内存中的hash连接
    • 连个数据集的大小
      • 若一个大表连接一个很小的表,则嵌套循环连接就比散列连接快
      • 若两个表都很大,则嵌套循环连接的CPU成本就比较搞
    • 是否由索引:单一有,选择索引连接。若连接属性上有两个B+树的索引的话,合并连接是好选择
    • 关系是否已经排序:有则选用合并连接
    • 结果是否需要排序:即使参与连接的是未排序的数据集,也可以考虑适用成本较高的合并连接
    • 连接的类型:等值?内连接?外连接?笛卡尔积?子连接?有些连接算法在某些情况下是不适用的
    • 数据的分布:若连接条件的数据是倾斜的,hash连接不是好选择
    • 多表连接:连接顺序的选择很重要

关系数据库系统的查询优化#

  • 有选择和连接操作时候,先做选择操作,这样参加连接的元组就可以大大减少,这就是代数优化,及通过对关系嗲书表达式的等价变换来提高查询效率。
  • 如果估算索引扫描比全表扫描更好,使用索引扫描和index join,就是物理优化

代数优化#

通过对关系代数表达式的等价变换来提高查询效率

关系代数表达式等价转换规则#

  • 笛卡尔积、自然连接的交换律和结合律
    • E1×E2E2×E1;(R×S)×TR×(S×T)E_1 \times E_2 \equiv E_2 \times E_1; \quad (R\times S)\times T \equiv R \times (S\times T)
    • E1E2E2E1;(RS)TR(ST)E_1 ⟗ E_2 \equiv E_2 ⟗ E_1; \quad (R ⟗ S) ⟗ T \equiv R ⟗ (S ⟗ T)
  • 投影的串接律
    • πA1,A2,...,An(πB1,B2,...,Bm(E))πA1,...,An(E) \pi_{A1,A2,...,An}(\pi_{B1,B2,...,Bm}(E)) \equiv \pi_{A1,...,An}(E)
    • 在同一个关系上,只需要做依次投影运算,且一次投影时选择多列同时完成
  • 选择的串接律
    • σF1(σF2(E))σF1F2(E)\sigma_{F1}(\sigma_{F2}(E)) \equiv \sigma_{F1 \land F2}(E)
    • 选择条件可以合并,使得一次选择运算就可检查全部条件,而不必多次过滤元组
  • 选择与投影的交换律
    • 假设:选择条件F只设计属性A1,…,An —> 先选择,后投影
    • σF(πA1,...,An(E))πA1,...,An(σF(E))\sigma_F (\pi_{A1,...,An}(E)) \equiv \pi_{A1,...,An}(\sigma_F(E))
    • 假设:F中有不属于A1,…,An的属性B1,…,Bm —> 先做带选择条件中的列投影,然后选择,再完成最外层投影
    • πA1,...,An(σF(E))πA1,...,An(σF(πA1,...,An,B1,...,Bm(E)))\pi_{A1,...,An}(\sigma_F (E)) \equiv \pi_{A1,...,An}(\sigma_F(\pi_{A1,...,An,B1,...,Bm}(E)))
  • 选择与笛卡尔积的交换律
    • 若F中设计的属性都是E1E1中的属性
    • σF(E1×E2)σF(E1)×E2\sigma_F (E_1 \times E_2) \equiv \sigma_F(E_1) \times E_2
    • F=F1F2F=F_1 \land F_2,并且F1F_1只涉及E1E_1中的属性,F2F_2中只涉及E2E_2中的属性,则:
    • σF(E1×E2)σF1(E1)×σF2(E2)\sigma_F(E_1 \times E_2) \equiv \sigma_{F_1}(E_1) \times \sigma_{F_2}(E_2)
    • F=F1F2F=F_1 \land F_2,F1F_1只涉及E1E_1中的属性,F2F_2涉及E1E_1E2E_2的属性,则:
    • σF(E1×E2)σF2(σF1(E1)×E2)\sigma_F(E_1 \times E_2) \equiv \sigma_{F_2}(\sigma_{F_1}(E_1)\times E_2)
    • 部分选择再笛卡尔积之前先做
    • 条件下推到相关的关系上,先做选择后做笛卡尔积运算,这样可以减小中间结果的大小
  • 选择与并的分配律
    • 假设:E=E1E2E= E_1 \cup E_2,E1,E2E_1,E_2有相同的属性名,
    • σF(E1E2)σF(E1)σF(E2)\sigma_F(E_1 \cup E_2) \equiv \sigma_F(E_1) \cup \sigma_F (E_2)
    • 条件下推到相关的关系上,先选择后做并运算,可以减小每个关系输出结果的大小
  • 选择与差的分配律
    • 假设E1,E2E_1,E_2有相同的属性名
    • σF(E1E2)σF(E1)σF(E)2\sigma_F(E_1-E_2) \equiv \sigma_F(E_1)-\sigma_F(E_)2
    • 先选择后做差运算
  • 选择与自然连接的分配律
    • 假设:E1,E2E_1,E_2使两个关系表达式
    • σF(E1E2)σF(E1)σF(E2)\sigma_F(E_1 ⟗ E_2) \equiv \sigma_F(E_1) ⟗ \sigma_F(E_2)
    • 先选择后做自然连接运算
  • 投影与笛卡尔积的分配律
    • E1,E2E_1,E_2是两个关系表达式,A1,...AnA_1,...A_nE1E_1的属性,B1,...,BmB_1,...,B_mE2E_2的属性,则
    • πA1,...,An,B1,...,Bm(E1×E2)πA1,...,An(E1)×πB1,...,Bm(E2)\pi_{A_1,...,A_n,B_1,...,B_m}(E_1 \times E_2) \equiv \pi_{A_1,...,A_n}(E_1) \times \pi_{B_1,...,B_m}(E_2)
    • 先投影后做笛卡尔积
  • 投影与并的分配律
    • E1,E2E_1,E_2有相同的属性名
    • πA1,...,An(E1E2)πA1,...,An(E1)πA1,...,An(E2)\pi_{A_1,...,A_n}(E_1 \cup E_2) \equiv \pi_{A_1,...,A_n}(E_1) \cup \pi_{A_1,...,A_n}(E_2)
    • 先投影后做并操作

查询树的启发式规则#

  • 转换的最终目的

    • 减少查询的开销(I/O次数)
  • 转换的直接目的

    • 减少中间关系的元组数、元组大小
  • 规则1:选择运算尽早执行(减小中间结果的规模)

  • 规则2:将选择、投影运算同时进行(避免重复扫描)

  • 规则3:把投影同其前或其后的双目运算结合(避免重复扫描次数)

  • 规则4:把选择运算与其前面的笛卡尔积运算结合起来一起计算(避免重复扫描并减小中间结果集的规模)

  • 规则5:把公共子表达式的运算结果存放在外存,作中间结果,使用时读入主存。如:视图表达式(避免重复计算)

  • 关系表达式代数优化算法

    • 运用选择的串接定律,得到选择运算“串”
    • 对每个选择运算符,利用等价变换尽量将其移至树的叶端
    • 对每个投影运算符,利用等价变换尽量将其移至树的叶端
    • 尝试将选择和投影串接合并成单个选择或投影,或选择后跟一个投影
    • 上述得到的语法树内节点分组:双目运算和它的父节点为一组。若其后代直至叶节点全部是单目运算,也合并为一组。笛卡尔积的子节点如果不能组合成等值的连接的选择,则二者不合并

物理优化#

  • 代数优化改变拆线呢语句中操作的次序和组合,不涉及底层的存取路径
  • 物理优化就是要选择高效合理的操作算法或存取路径,求得优化的计划。常常先使用启发式规则选取若干较优的候选查询方案,然后分别估算这些候选方案的执行代价,从而选取代价最小的作为执行计划

基于启发式规则的优化#

  • 选择操作的启发式规则:
    • 对于小关系,使用全表扫描了,即 使选择列上有索引
    • 对大关系
      • 如果是主码值上的等值查询“主码=值”,使用主码索引
      • 如果是非主码值上的等值查询,在选择比例<10%的情况下,使用索引(如果有);否则使用全表扫描
      • 如果非等值或范围查询,在选择比例<10%的情况下是,使用索引(如果有);否则使用全表扫描
      • 对于用AND连接的合取选择条件,如果有涉及折写属性的组合索引,优先采用组合索引扫描方法;如果某些属性上有一般索引,则可以用索引扫描方法;否则使用全表顺序扫描
      • 对于用OR连接的析取选择条件,一般使用全表顺序扫描
  • 连接操作的启发式规则
    • 如果2个表都已经按照连接属性排序,使用选择-合并方法
    • 如果一个表在连接属性上有索引,选择索引连接方法
    • 如果上面两个规则都不使用,其中一个表较小,使用hash join方法
    • 可以选用嵌套循环方法,并选择其中占用块较小的表,作为外表(外循环的表)

基于代价的优化#

  • 为什么采用启发式规则

    • 可能造成查询优化过程的开销大于获得的查询开销的大小,得不偿失
  • 查询代价估算

  • 查询代价估算基于CPU代价和I/O代价,

    • 总代价=I/O代价+CPU代价 总代价=I/O代价+CPU代价
    • COST=Pa_page_cpu_time+WTCOST = P * a\_page\_cpu\_time + W * T
    • P是计划运行时访问的页面数,a_page_cpu_time是每个页面读取的时间开销,其成绩反应了I/O开销
    • T为访问的元组数量,如果是索引扫描,还要考虑索引读取的开销,反应了数据读取到内存的CPU开销
    • W为权重因子,表明I/O到CPU的相关性,有称选择率

第十章 数据库恢复技术#

事务的基本概念#

  • 事务
    • 定义:事务是用户定义的一组数据库操作,这组操作要么都做,要么都不做,不可分割。
    • 是恢复和并发控制的基本单位
  • 事务和程序比较
    • 关系数据库事务:一个/一组SQL语句,或一段程序
    • 一个程序通常包含多个事务
  • 定义事务
    • 显式定义方式
      begin transaction
      SQL语句1
      SQL语句2
      ...
      commit work/rollback work
    • 隐式方式:当用户没有显式定义事务时,DBMS按缺省规定自动划分事务
    • 某种环境或者程序中的一条SQL语句,应用程序或操作窗口退出
  • 事务的特性(ACID)
    • 原子性atomicity:要么全做,要么全不做
    • 一致性consistency:数据库中只包含成功事务提交的结果,没有夭折事务残留的修改
    • 隔离性isolation:不受其它并发执行事务的影响
    • 持久性durability
  • 事务的两段提交:
    • 事务执行的读写操作,只有正常提交了,才永久存入DB,之前都是放在缓冲区中。如果事务失败,则DBMS撤销它对DB和其它事务的影响,恢复到执行事务之前的状态

故障的种类#

  • 事务内部故障
    • 特点:非预期事务故障:事务没有达到预期的重点(commit或rollback),事务夭折。夭折事务对数据库的部分修改可能已写入数据文件(数据库可能处于不正确、不一致状态)
    • DBMS仍在正常运行
    • 事务故障恢复:撤销事务,DBMS自动完成
  • 系统故障
    • 特点:
      • 整个系统的正常运行突然被破坏,DBMS不能正常运行
      • 所有正在运行的事务都非正常终止
      • 内存数据丢失或不再可靠;外存数据不受影响
      • DB处于不正确或不一致状态:一些尚未完成事务的结果可能已送入DB;已完成事务的结果可能部分未送入DB;已完成事务的结果全部未送入DB(未提交)
    • 发生故障时,事务未提交:
      • 恢复策略:强行撤销undo所有未完成事务
    • 发生系统故障时,事务已提交,但缓冲区中的信息尚未完全写回到磁盘上:
      • 恢复策略:重做redo所有已提交的事务
  • 介质故障:硬故障,外存发生故障
    • 介质故障恢复:装入副本或镜像。

恢复的实现技术#

数据转储#

  • 静态转储与动态转储
    • 静态:
      • 在系统无运行事务时进行的转储操作
      • 转储开始时数据库处于一致性状态
      • 转储期间不允许对数据库的任何存取、修改活动
      • 得到的一定是一个数据一致性的副本
      • 优点:实现简单
      • 缺点:停止了一切事务运行,降低了数据库的可用性
        • 转储必须等待正在运行的用户事务结束
        • 新的事务必须等待转储结束
    • 动态:转储操作与用户事务并发进行,转储期间允许对数据库进行存取或修改
      • 优点:不用等待正在运行的用户事务结束,不会影响新事务的运行
      • 缺点:不能保证副本中的数据正确有效
      • 解决:需要把动态转储期间各事务对数据库的修改活动等级下来,建立日志文件
      • 后备副本加上日志文件才能把数据库恢复到某一时刻的正确状态。
  • 海量转储与增量转储
    • 海量转储:定期或不定期将DB全部数据转储
      • 优点:简单
      • 缺点:重复转储,转储量大;停止运行(多为静态转储)
    • 增量转储:只转储上次转储后更新过的数据:
      • 优点:备份量小
      • 缺点:恢复过程比较复杂

日志#

  • 先写日志后写数据规则
  • 对日志文件中的记录进行REDO的时候,要按照日志序号递增的顺序进行,即正向扫描日志文件进行REDO
  • 对日志文件中的记录进行UNDO的时候,要按照日志序号递减的顺序进行,即反向扫描日志文件进行UNDO

恢复策略#

  • 事务恢复方法:利用log UNDO此事务对DB的修改

  • 步骤:UNDO操作

    • 反向扫描文件日志,查找该事务的更新操作
    • 对该事务的更新操作执行逆操作。
    • 继续上两条
    • 读到事务开始标记,故障恢复完成
  • 特点:DBMS自动完成

  • 系统故障的恢复

  • 目标:撤销故障发生时未完成的事务,重做已完成的事务

  • 步骤:UNDO未完成事务,REDO已完成事务

    • 正向扫描日志文件,找出在故障发生前已经提交的事务,将其事务标识记入重做队列;同时找出故障发生时未完成的事务,将其事务标识记入撤销队列。
    • 对撤销队列中的各个事务进行撤销处理:反向扫描日志文件,对每个UNDO事务执行UNDO操作
    • 对重做队列中的各个事务进行重做REDO处理:正向扫描日志文件,对每个REDO事务重新执行等级的操作。
  • 特点:由DBMS在重启时自动完成

  • 介质故障的恢复

  • 目标:数据和日志文件被破坏时的恢复,维护事务的持久性

  • 步骤:

    • 装入最新的后背数据库副本,使数据库恢复到最近一次转储时的一致性状态
      • 对于动态转储的数据库副本,还需要转储时刻的日志文件副本,利用恢复系统故障相同的方法,才能恢复到一致性状态
    • 装入有关的日志文件副本,重做已完成的事务
      • 特点:需要DBA干预。DBA负责:重装最近转存的数据库副本和有关的各日志文件副本,执行系统提供的恢复命令

checkpoint技术#

  • 基本策略:周期性的对日志做检查点,保存DB状态,避免故障恢复时检查整个日志
  • 方法:在日志文件中增加一类新的记录—检查点checkpoint记录,并增加一个”重新开始文件“。周期性执行以下步骤
    • 将日志缓冲区中的日志记录写入磁盘
    • 在日志文件中写一个检查点记录
    • 将数据缓冲区中的数据写入磁盘DB中
    • 将检查点记录在日志文件中的地址写入重新开始文件
  • 检查点记录的内容:
    • checkpoint时刻所有正在执行的事务清单
    • 这些事务最近一个日志记录的地址
  • 重新开始文件的内容:
    • 记录各个检查点记录在日志文件中的地址
  • 使用检查点方法可以改善恢复效率:
    • 当事务T在一个检查点之前提交:
      • T对数据库所做的修改已写入数据库
      • 写入时间使在这个检查点建立之前或在这个检查点建立之时
      • 在进行恢复处理时,没有必要对事务T执行REDO操作
  • 利用checkpoint进行恢复的步骤:
    • 根据重新开始文件中最后一个检查点记录的地址,在日志文件中找到最后一个检查点记录
    • 由检查点记录得到该检查点记录的事务清单active-list
      • 建立两个事务队列:undo-list,redo-list
      • 把active-list暂时放入undo-list对立,redo队列暂时为空
    • 从检查点开始正向扫描日志文件,直到日志文件结束
      • 如有新开始的事务T,把T暂时放入undo-list队列
      • 如有提交的事务T,把T从undo-list移到redo-list
    • 对undo-list的每个事务执行undo操作,对redo-list的每个事务执行redo操作

第十一章 并发控制#

概述#

  • 并发控制是为保证多用户并发操作数据库中信息时的正确性、一致性所采取的措施

  • 事务调度

    • 事务的执行顺序称为一个调度,表示事务的指令在系统中执行的时间顺序
    • 一组事务的调度必须保证
      • 包含了所有事务的操作指令
      • 一个事务中指令的顺序必须保持不变
    • 串行调度
      • 属于统一事务的指令紧挨在一起
      • 每个时刻只有一个事务运行,其它事务必须等到这个事务结束以后方能运行
      • 对于有有n个事务的事务组,可以有n!n!个有效调度
      • 缺点:不能充分利用系统资源,发挥数据共享资源的特点
    • 交叉并发方式
      • 在单处理机系统中,事务的并行执行是这些并行事务的并行操作轮流交叉运行
      • 单处理机系统中的并行事务并没有真正的并行运行,单能够减少处理机的空闲时间,提高系统的效率
    • 同时并发方式
      • 多处理机系统中,每个处理机可以运行一个事务,多个处理机可以同事运行多个事务,实现多个事务真正的并行运行
      • 并发执行的优点:
        • 一个事务由不同的步骤组成,所设计的系统资源也不同.各步骤并发执行,提高系统的吞吐量
        • 如果各个事务设计数据库的不同部分,采用并发会减少平均响应时间
      • 核心问题:在保证一致性的前提下最大限度的提高并发度
  • 并行调度的问题:带来数据的不一致性

    • 丢失更新
      • 两个以上事务从DB中读入同一数据并进行修改,其中一事务(后提交的事务)的提交结果破坏了另一事务(先提交事务)的提交结果,导致先提交事务对DB的修改被丢失.这种现象使数据库操作出现严重错误.
    • 不可重复读
      • 同一事务重复读同一数据,但获得结果不同,即从数据库中得到了不一致的数据(可能因为其它并发修改了数据库中的数据)
    • 读“脏”数据
      • 读未提交随后又被撤销(rollback)的数据.即从数据库中获取了临时性数据
  • 并发控制的任务:用正确的方法调度并发操作,使一个事务的执行不受其他事务的干扰,从而避免数据的不一致现象

  • 并发控制:正确的方式调度并发事务,使得一个事务的执行不受其他事务的干扰,避免造成数据的不一致性

    • 封锁
    • 时间戳
    • 乐观控制法
    • 多版本并发控制

封锁#

  • 定义:事务T在每个数据对象操作之前,先相系统发出请求,加锁,于是事务T对这个数据对象就有一定的控制,直到T释放它的锁为止

  • 锁的类型

    • 排它锁(X锁,写锁):若事务T对数据R加上X锁,啧其他事务不能对R进行任何封锁,保证了其他事务不能读取和修改R
    • 共享锁(S锁,读锁):若事务T对数据R加上了S锁,啧其他事务能对R加S锁,保证了其他事务能读取单不能修改R
  • 封锁的粒度:

    • 封锁对象的大小称为封锁的粒度
    • 关系数据库的封锁对象:属性之、元组、关系、索引
  • 封锁规则

    • 对于将要存取的数据须先申请加锁,加锁成功才能存取
    • 已被加锁的数据不能再加不相容锁
    • 一旦退出使用应适时释放锁
    • 未被加锁的数据不可以对之解锁
  • 常用的封锁协议

    • 支持一致性维护的三级封锁协议
      • 策略:1级封锁协议+事务Ti在读取Di之前必须对Di加s锁,直至Ti结束后即可释放该s锁
      • 功能:防止丢失更新、防止读“脏”、防止读不可重复
    • 支持并行调度可串行化的两段封锁协议
    • 避免死锁的协议
  • 活锁:事务因故永远处于等待状态

    • 预防方法:FCFS(first come first Server):先来先服务
    • 对于事务由优先级的系统,可设置一个最长等待时间,与优先级结合,调度事务的执行
  • 死锁:两个或两个以上事务均处于等待状态,每个事务都在等待其中另一个事务封锁的数据,导致任何事务都不能继续执行

    • 产生条件:
      • 互斥(排它性控制)
      • 不可剥夺(释放前,其它事务不能剥夺)
      • 部分分配(每次申请一部分)
      • 环路(每事务获得的数据同时又被另一事务请求)
    • 解决办法:破坏死锁产生的条件
      • 预防:一次封锁法:每个事务先一次获得其需数据的全部锁
        • 特征:简单,无死锁;粒度大,并发性低;难以实现精确确定封锁对象。
      • 预防:顺序封锁:按照预先确定的数据封锁顺序实行封锁
      • 预防:时间戳优先级法
        • wait-die:老的时间戳更高优先级,优先级低的如果请求锁,则撤回。
        • wound-wait:请求的事务有更高的优先级,则撤销持有锁的事务,释放锁。
      • 等待图法:构造等待图,周期性检测,如果出现回路,则选择一个处理死锁代价最小的事务,释放该事务的所有锁

并发调度的可串行性#

  • 可串行化调度:当且仅当多个事务并发执行的结果与该事务任一串行执行的结果相同时,则该并发执行是可串行化的

  • 可串行性是并发事务正确调度的唯一准则

  • 一个给定的并发调度,当且仅当它是可串行化的,才认为是正确调度

  • 冲突可串行化——判断可串行化调度的充分条件:对于一个并发调度Sc,在保证冲突操作次序不变的情况下,如果通过交换不冲突操作可以得到一个串行调度,则Sc为冲突可串行化调度

  • 冲突操作:不同事务对同一个数据的读写操作或写写操作

  • 交换原则:

    • 不同事务的冲突操作不能交换次序
    • 同一事务的两个操作不可交换

两段锁协议#

  • 2PL是保证并发操作调度的可串行化而提供的封锁协议
  • 策略:
    • 在对任何数据读、写之前,必须先获得该数据的锁
    • 在释放一个封锁之后,该事务不能再申请任何其它锁
  • 定理:若所有并发事务都遵循两段锁协议,则最这些事务的所有并发调度都是可串行化的
  • 说明:
    • 是可串行化调度的充分条件
    • 并性执行结果一定是正确的,但是不能防止死锁
      • 一次封锁法遵守两段锁协议,但是两段锁协议不要求事务必须一次将所有要使用的数据都枷锁,所以可能死锁
    • 2PL保证冲突可串行化,但是存在级联撤销的问题
      • 解决:再释放锁(shrinking phase)阶段,只有commit或abort时才一次性释全部锁
    • 两段锁 VS 三级封锁协议
      • 两段锁保证并发调度的正确性
      • 三级封锁协议在不同程度上保证数据的一致性
      • 遵循第三级封锁协议必然遵守两段锁协议

封锁的粒度#

  • 封锁对象的大小称为封锁粒度
  • 封锁对象:逻辑单元,物理单元
    • 逻辑单元:属性值、属性值集合、元组、关系、索引项、整个索引、整个数据库
    • 物理单元:页(数据页或索引页)、物理记录等
  • 封锁粒度与系统的并发度和并发控制的开销密切相关
    • 粒度越大,能够封锁的数据单元越少,并发度越小,系统开销越小

多粒度封锁#

  • 允许多粒度树中的每个节点被独立的加锁
  • 对一个节点加锁以为着这个节点所有后裔节点页被加同样类型的锁
数据库复习
https://blog.cassiusblack.top/posts/hust-cs-database/
Author
Cassius Black
Published at
2024-07-06
License
CC BY-NC-SA 4.0