Database System Concepts Note

Database System Concepts Notes

Chapter 1 Introduction

1.1 数据、数据库、数据库系统、数据库管理系统

  • 数据:一条条记录
  • 数据库:The collection of data, usually referred to as the database.
    • 数据库按照某种结构,有序的组织数据
    • 数据量大,有关联,有结构,可共享
  • 数据库系统:开发的应用系统(包含一组由关联的数据和一组处理数据的程序)
    • 注:后台有数据库支持的网站或者应用都可称为数据库系统
    • 系统的演化:记录(若干个属性) → \to 一个表 → \to 一个数据库 → \to DBMS(Mysql) → \to Java访问 → \to 系统
  • 数据库管理系统:A database-management system (DBMS) is a collection of interrelated data and a set of programs to access those data.
    • Oracle、MySql、MongoDB

1.2 使用数据库系统的目的

1.2.1 关系型数据库的共同特点

基于关系模型

e.g. 所有关系型数据库都基于 SQL 国际标准

但是,非关系型数据库没有共同的理论基础

1.2.2 使用文件存储和使用数据库存储的对比

如果使用 Excel、txt 文件存储数据

优点:方便

缺点:不安全、并发访问差、查询不方便、文件和文件之间没有关联

e.g. 大学的数据如果使用 txt 存储,假设有学生基本信息、学生学习成绩、学生的活动三个 txt 文件。但这三个文件是有关联的,使用 txt,excel 都难以体现文件之间的关联。

1.2.3 使用文件系统的不足

  1. 数据的冗余和不一致

冗余:同一数据的重复存储 → \to 在修改时造成数据的不一致,浪费了存储空间

e.g. 学生的手机号存储在5个文件中,在学生手机号更换时,造成了数据错误。

  • 在经典的关系模型理论中,一定要消除冗余
  • 在当前的一些应用中,为了加快响应速度,反而有意的保留一些冗余
  1. 不易存取
  2. 孤立
  3. 数据的完整性得不到保障
  • DBMS 会使用一些约束机制,保证数据的正确性和完整性
  1. 并发异常

  2. 安全问题

*1.3 View of Data

1.3.1 Data Abstraction 数据抽象

物理层抽象:生成的物理文件,真正的数据

逻辑层抽象:数据之间的关系,在软件中的表现方式

视图层:数据的局部,有好多个视图层

如果将数据抽象比作一头大象

  • 物理层(内模式)是一个大象实体 (10个表)

  • 逻辑层(概念模式)是百科全书中的大象 (10个表)

  • 视图层(外模式)是大象的局部 ( ≤ \le 10 个表)

使用视图层的目的
  • 为了安全
    • 为了数据库的安全考虑,在实际开发时通常只给开发人员展示视图层的部分,甚至对表名、字段名做模糊处理
    • 在一般的开发中,数据库的结构严格保密
  • 简化数据库结构

1.3.2 Instances and Schemas 实例与模式

模式和实例对应面向对象中的类和实例

模式:数据库的结构

实例:在某一时刻,数据库的状态,是经常变化的

1.3.3 Data Models 数据模型

  • 一组软件工具集合,用以描述:数据、数据之间的联系、数据语义、数据约束
!数据模型的三要素
  • 数据结构:去组织数据
    • C H − 2 CH-2 CH2 关系模型的数据结构
  • 操作数据:定义一组命令去操作数据 C R U D CRUD CRUD
    • C H − 6 CH-6 CH6 关系代数,理论上操作
    • C H − 3 ∼ C H − 5 CH-3\sim CH-5 CH3CH5 SQL 实际上的操作,SQL 语句
  • 一组规则(约束):保证数据的完整性和正确性

Chapter 2 Intro to the Relational Model

The relational model is today the primary data model for commercial data processing applications.

2.1 Structure of Relational Databases

  • 数据结构:一张二维表
    • 表对应的每一列:属性/ 字段 (attribute)
    • 表的每一行的值:元组 (tuple) / 记录 (record)

2.1.1 属性的特点

  • 每一个属性有允许的取值范围
  • 每一个属性具有原子性,不可分
  • 可以有 null 空值
    • Definition: The null value is a special value that signifies that the value is unknown or does not exist.
    • null 会影响查询效率,通常在实际操作时使用默认值代替 null

2.1.2 关系模型的优点

优点

  • 有严谨的数学基础 → \to 集合论
  • 简单清晰

缺点

  • 只能存适合用二维表描述的结构化数据,应用场景受限

对关系的形式化定义

11/100 ch2

2.3 Keys 码/关键字

码 (Key) 具有唯一性,由一个或者多个属性构成,能够唯一的标识某一条记录,在数据库查询时,通过码来加快查询速度

  • 查询优化 → \to 索引文件 (对于每一个主码属性,系统会自动的创建索引文件)

2.3.1 码的类型

  • superkey 超码:任意属性集合,可以用来区别元组
    • 可能会有多余(冗余)的属性
    • 不是最小化的一个属性集合
  • candidate key 候选码:候选码的任意子集不是超码
    • 对超码进行了最小化,去除了冗余的属性
    • 在一个关系里,候选码可以有多个
    • 建表时选一个候选码作为主码使用
    • e.g. 在一个学生关系中,学生的身份证号和学号都是候选码,但是 { s t u d e n t I d , i d } \{studentId,id\} {studentId,id} 不是一个候选码
  • primary key 主码:在多个候选码中挑选一个候选码供当前关系使用
    • 插入一条新记录的时候,主码的值一定要唯一
    • 修改一条记录的主码时,修改的主码值也要唯一
    • 主码值不能为空,必须要有值
    • DBMS 根据主码上创建搜索索引
    • 一般在实际操作中,使用 DBMS 系统自动生成主码
    • 实体完整性约束:对主码属性取值的约束
      • 一般情况下的主码选用:属性本身是唯一的,属性本身较少变化
  • foreign key 外码:针对两个表,体现两个表之间的一种关系,这两个表可以是同一个表(自连接)
    • 可以同名,可以不同名,但是数据类型必须一致
    • 例如,有学生表和课程表,课程表 r 2 r_2 r2 和学生表 r 1 r_1 r1 都有属性 i d id id i d id id r 2 r_2 r2 中做主码,在 r 1 r_1 r1 中不做主码,则这个属性就是 r 1 r_1 r1 的外码
      • r 1 r_1 r1 参照关系 (referencing relation)
      • r 2 r_2 r2 被参照关系 (referenced relation)
    • 外码在本表中不能做主码
    • 参照完整性:外码一旦建立,就会自动检测相关联的表是否符合要求,外码的取值要参考参考表。A referential integrity constraint requires that the values appearing in specified attributes of any tuple in the referencing relation also appear in specified attributes of at least one tuple in the referenced relation.
      • 取空值、 r 2 r_2 r2 中某个元组的主码值
      • 例如,在学生的选课课程表中要约束外码取值 i d {id} id ,这个外码一定要在关联的学生表中存在。同时,也不能在参照关系中删除已经在被参照关系中包含的元组

PS:对于关系型的 DBMS ,自动支持了实体完整性和参照完整性约束。对于 DBA 只要定义主码和外码,DBMS 会自动检查实体完整性和参照完整性约束。

2.3.2 关于码的一些实际例子

e.g.1 学生实体、专业实体

学生(学号,姓名,性别,专业号,年龄)

专业(专业号,专业名)

e.g.2 学生、课程、学生与课程之间的联系

学生(学号,姓名,性别,专业号,年龄)

课程(课程号,课程名,学分)

选修(学号,课程号,成绩)

  • 复合属性主码:如果只用一个属性做主码,不能唯一的区分每一个元组

  • 此表中有两个外码:在选修表中,单独的学号是外码(对于学生表),单独的课程号是外码(对于课程)

  • 在选修表中,学号和课程号同时收到了实体完整性(主码约束)和参照完整型约束(参考参考关系中的值)。也就是说

    • 选修主码:学号,课程号
    • 外码 1 :学号,在学生表中存在,且不能为空(它是一个主码
    • 外码 2 :课程号,在课程表中存在,且不能为空(它是一个主码

Chapter 3 Introduction to SQL

3.1 Overview of the SQL Query Language

关系代数:理论

SQL : 实践

3.1.1 当前使用 SQL 语言的两种方式
  • DBA → \to SQL → \to 管理 DBMS
  • 开发人员 → \to SQL 嵌入到编程语言中 → \to 访问 DBMS 中的某一个数据库 (CRUD)
3.1.2 数据库服务器

登陆前的准备:通过计算机 → \to 管理 → \to 服务 → \to MySQL 查看服务是否启动

  1. 成功登陆 登录信息(连接字符出)
  • 用户名

  • 密码

  • 端口号 3306(default)

  • 数据库服务器的地址(本机 127.0.0.1)或者计算机名(localhost)

  1. 客户端:DBA 命令行/可视化工具

  2. 访问和操作数据库

3.1.3 数据库类型
  • 系统数据库
    • information_schema
      • 存储数据库对象信息(如用户表信息,列信息等),不能修改
    • performance_schema
      • 存储数据库服务器性能参数信息,不能修改
    • sys
      • 以视图形式显示更易理解的系统元信息
    • mysql
      • 存储 Mysql 配置信息,用户权限信息等
  • 用户数据库
    • 用户创建的数据库
  • 学习数据库
    • sakila 和 world,可删除
3.1.4 创建数据库
  • 输入数据库名称:要求唯一,一般小写,英文名称且有意义,不要太长
  • 选择字符集:一般使用 utf8
  • 数据库排序规则:一般使用 utf8_general_ci

3.2 SQL (Structure Query Language)

3.2.1 SQL的基本结构 查询

  • 关系代数是 SQL 查询的理论基础

  • select 最终的结果投影

	select 字段1,字段2....字段n
  • from
from1,表2...n
  • where 选择运算
where 筛选条件
  • group by 分组+聚集函数
group by 分组字段
  • order by
    • 排序的时候参考 UTF8 来排序
order by 排序字段
  • 重命名:as 可以省略,表进行自连接的时候,一定要对表重命名
  • like 模糊查询
    • % 匹配任意多个字符
    • _ 匹配一个字符
    • * 选出所有

3.2.2 SQL语句的注意点

  1. 大小写敏感,一般数据库名,表名,字段名都是小写
  2. 一条 SQL 命令以分号结束
  3. 所有的符号都要在半角下输入
  4. -- 为单行注释 /**/ 为多行注释
  5. 保留字不要给数据库名,表名,字段名命名
  6. 分行写每一个关系
  7. select * 表示要显示表中的所有字段
  • 在学习,实验中可以用
  • 在实际开发中不要用
  1. salary / 12 广义投影
  2. 多表查询 → \to 关系代数(笛卡尔积)
  3. 有些 DBMS 不支持自然连接,所以在开发中不使用,避免换库时的麻烦

3.5 Set Operations ans Null Values

3.5.1 关系代数的并交差

  • 前提条件
    • 两个查询结果中的字段的个数要相同
    • 相对应的属性的域要相同

3.5.2 Union

  • union 去重复
  • union all 不去重复

3.5.3 Intersect

  • mySQL 不支持交运算,使用嵌套的 select 实现

3.5.4 Except

  • mySQL 不支持差运算,使用嵌套的 select 实现

3.5.5 Null

  • 查询空值不可以使用等号

3.7 Aggregate Function 聚集函数

  • 分组 + 聚集函数
    • 使用 group by 加上字段:根据指定的字段进行分组

      • 如果没有使用 group by
    • select

      • 被分组后的可以加到 select 子句中
      • 小组类型的数据
    • having : 对分组后的记录进行筛选

      • 一定和 group by 搭配使用 having + 筛选条件
      select
      from
      where + 筛选条件 -- 针对所有的记录
      group by -- 分组
      having + 筛选条件 -- 针对分组后的记录再做筛选
      
    • 配合相应的聚集函数进行运算

      • sum()
      • avg()
      • count()
      • max()
      • min()

3.8 Nested Subqueries 嵌套子查询

  • 定义: 一个 select 语句嵌套在另一个 select 语句中

  • 不同的 DBMS 嵌套的方式不同

  • 出现的位置

select t1, t2 = select子句
from r1, r2 = select子句
where 字段1 in/=/>= select子句
  • 目的: 分步查询, 降低查询难度

3.8.1 集合成员

  • in 测试元组是否是集合中的成员
  • not in 测试元组是否不是集合中的成员
  • in/not in 的执行顺序: 从最里层的查询开始执行
  • in/not in 等价于 连接查询/and/or

3.8.2 集合的比较

  • 至少比某一个要大:使用 > some 表示

  • 比所有的都大: 使用 > all 表示

注意

  • = some 等价于 in
  • < > some 不等价于 not in
  • < > all 等价于 not in
  • = all 不等价于 in

3.8.3 空关系测试

  • exists 结构在作为参数的子查询非空时返回 true (i.e. 判断子查询的查询结果中有没有记录)
    • exists
      • 有记录 true
      • 没有记录 false
    • not exist
      • 有记录 false
      • 没有记录 true

通常写法 select * exists

  • 相关子查询:子查询不能独立执行,要依赖于父查询
    • 谓词 exists 的查询是外层的查询先执行, 再做到内层, 多重循环
  • 不相关子查询:子查询可以独立执行,给父查询提供信息

PS:除法:一个集合是否包含另一个集合中的所有数据,只能通过 not exist 间接实现

e.g. 查询2009年秋季学期和2010年春季学期同时开课的课程

SELECT *
FROM
    section AS S
WHERE
      semester = 'Fall'
  AND year = 2009
  AND EXISTS
          (
              SELECT *
              FROM
                  section AS T
              WHERE
                    semester = 'Spring'
                AND year = 2010
                AND S.course_id = T.course_id
          );

注意到,来自外层查询的一个相关名称可以用在 where 子句的查询中

使用了外层查询相关名称的子查询称为相关子查询

3.8.4 重复元组存在性测试

如果作为参数的子查询结果中没有重复的元组, unique 结构将返回 true

e.g. 找出所有在2009年最多开设过一次的课程

select T.course_id
 from course as T
 where unique(select R.couse_id
              from section as R
              where T.course_id=R.course_id and 
              R.year=2009);

SELECT
    T.course_id
FROM
    course AS T
WHERE
        1 >= ( -- 1代表什么
        SELECT
            COUNT(R.course_id)
        FROM
            section AS R
        WHERE
              T.course_id = R.course_id
          AND R.year = 2009
    )

3.8.5 from子句中的子查询

任何 select-from-where 返回的结果都是关系, 因而可以被插入到另一个 select-from-where 中任何关系可以出现的位置

3.8.6 with子句中的子查询

with子句提供定义临时关系的方法,这个定义只对包含with的子句的查询有效

-- 工资总额大于所有系平均工资总额的系

WITH
    dept_total(dept_name, value) AS
        (SELECT
             dept_name,
             SUM(salary)
         FROM
             instructor
         GROUP BY
             dept_name
        ),
    dept_total_avg(value) AS
        (SELECT
             AVG(value)
         FROM
             dept_total
        )
SELECT
    dept_name
FROM
    dept_total,
    dept_total_avg
WHERE
    dept_total.value >= dept_total_avg.value

3.8.7 select子句中的子查询

  • 也被称为标量子查询

select 子句中可以嵌套 select-from-where , 当且仅当 select 的结果作为一个属性

3.9 数据库的修改

3.9.1 删除

  • 只能删除整个元组,不能删除某些属性上的值
delete from r
where P;

其中, P P P 代表一个谓词, r r r 代表一个关系. delete 语句首先从 r r r 中找出所有使得 P ( t ) P(t) P(t) 为真的元组 t t t, 然后把他们从 r r r 中删除. 如果省略 where 子句, 则 r r r 中的所有元组都将被删除

3.9.2 插入

语法

insert into course
	values('CS-437', 'Database Systems', 'Comp. Sci.', 4);

或者

insert into course(course_id, title, dept_name,credits)
	values('CS-437', 'Database Systems', 'Comp. Sci.', 4);

在查询结果的基础上插入元组

e.g. 让Music系的每个修满144学分的学生成为教师, 其工资为18000美元

INSERT INTO
    instructor
SELECT -- 将id, name, dept_name, 18000 作为四个项插入instructor
    ID,
    name,
    dept_name,
    18000
FROM
    student
WHERE
      dept_name = 'Music'
  AND tot_cred > 144;

注意: 应该在执行插入操作之前执行完 select 语句, 应该避免执行会导致无限循环的 insert-select 操作

insert into student
	select *
	from student

3.9.3 更新

在不改变整个元组的情况下改变其部分属性的值

语法

update instructor
set salary = salary * 1.05

update instructor
set salary = salary * 1.05
where salary < 70000

当要对不同的群体进行操作时, update 的顺序十分重要

e.g. 对工资超过100000美元的教室涨3%工资,其余涨5%

update instructor
set salary = salary * 1.03
where salary > 100000

update instructor
set salary = salary * 1.05
where salary <= 100000

注意: 上面两个 update 语句的顺序十分重要, 如果改变这两个语句的顺序, 那些工资略低于100000的教师将会涨8%的工资

使用Case确定更新顺序

update instructor 
set salary = case
		when salary <= 100000 then salary * 1.05
		else salary * 1.03
	end

标量子查询在update中的应用

UPDATE student
SET
    tot_cred=(
        SELECT
            SUM(credits)
        FROM
            takes,
            course
        WHERE
              takes.course_id = course.course_id
          AND student.ID = takes.ID
          AND takes.grade <> 'F'
          AND takes.grade IS NOT NULL);


SELECT *
FROM
    instructor
LIMIT 3,5;

Appendix MySQL 补充语法

  • limit n:只显示查询结果中的 n n n 条记录
SELECT dept_name,AVG(salary) AS avg_salary 
FROM instructor
GROUP BY dept_name
ORDER BY avg_salary DESC
LIMIT 2;
  • limit 分页查询
SELECT *
FROM
    instructor
LIMIT 3(开始查询的位置),5(结束查询的位置);

分页查询公式:
查询第 pageIndex 页,每页显示 pageSize 条:

Select * from student LIMIT (pageIndex -1) * pageSize,pageSize;
  • with rollup :求小计

group by + with rollup:表示在进行分组统计的基础上再次对每一小组进行汇总统计

SELECT
    country.`Code`,
    SUM(city.`Population`)
FROM
    country,
    city
WHERE
    country.`Code` = city.`CountryCode`
GROUP BY
    country.`Code`; -- 只根据 code 分组
    
SELECT
    country.`Code`,
    city.`ID`,
    SUM(city.`Population`)
FROM
    country,
    city
WHERE
    country.`Code` = city.`CountryCode`
GROUP BY
    country.`Code`, city.`ID`; -- 根据 code 和 id 分组

SELECT
    country.`Code`,
    city.`ID`,
    SUM(city.`Population`)
FROM
    country,
    city
WHERE
    country.`Code` = city.`CountryCode`
GROUP BY
    country.`Code`, city.`ID`
WITH
    ROLLUP;
-- 根据 code 和 id 分组,再对每个 code 中的 id 进行汇总

#Chapter 4 Intermediate SQL

4.1 Join 连接查询

4.1.1 INNER JOIN

/*4.1.1 inner join*/
/*1.查询学生的选课情况,使用内连接*/
SELECT *
FROM
    student
        JOIN takes ON student.ID = takes.ID
;

-- 这是内连接,也可写成 inner join
SELECT *
FROM
    student
        INNER JOIN takes ON student.ID = takes.ID
;

-- 也可以用多表连接的方式完成
SELECT *
FROM
    student,
    takes
WHERE
    student.ID = takes.ID;
-- 笛卡尔积后再等值连接查询

4.1.2 OUTER JOIN

/*4.1.2 OUTER JOIN 外连接*/
/*1. 查询出所有学生的选课情况,包括没有选课的学生,使用左外连接 */

SELECT *
FROM
    student
        LEFT OUTER JOIN takes ON student.ID = takes.ID;


/*2. 找出没有选修课程的学生*/
SELECT *
FROM
    student
        LEFT OUTER JOIN takes ON student.ID = takes.ID
WHERE
    course_id IS NULL;

/*3. 查询出所有学生的选课情况,包括没有选课的学生,使用右外连接*/
SELECT *
FROM
    takes
        RIGHT OUTER JOIN student ON student.ID = takes.ID
;

/*4. 显示Comp.Sci.系的所有学生以及他们在2009年春季选修的所有课程段的列表.*/
/*mysql 不支持以下代码。*/
/*
SELECT *
FROM
    (SELECT
         id,
         name
     FROM
         student
     WHERE
         dept_name = 'Comp. Sci.') full OUTER JOIN
 (SELECT id
 FROM takes
 WHERE semester='Spring' AND YEAR=2009)
ON student.id= takes.id;
 */
/*由于 Mysql 不支持全外连接,所以只能用左外连接并上右外连接*/
SELECT *
FROM
    (SELECT
         id,
         name
     FROM
         student
     WHERE
         dept_name = 'Comp. Sci.')
        AS Cstudent1 (id, name)
        LEFT OUTER JOIN
        (SELECT
             id
         FROM
             takes
         WHERE
               semester = 'Spring'
           AND year = 2009)
            AS Cspring1 (id)
        ON Cstudent1.id = Cspring1.id
UNION
SELECT *
FROM
    (SELECT
         id,
         name
     FROM
         student
     WHERE
         dept_name = 'Comp. Sci.')
        AS Cstudent2 (id, name)
        RIGHT OUTER JOIN
        (SELECT
             id
         FROM
             takes
         WHERE
               semester = 'Spring'
           AND year = 2009)
            AS Cspring2 (id)
        ON Cstudent2.id = Cspring2.id;





4.2 视图的创建和使用

  • 视图的作用
    • 安全性:隐藏基本数据,可使用权限机制控制用户的访问,
    • 查询性能提高:可直接基于视图查询
    • 提高了数据的独立性

4.2.1 创建视图

-- 4.2.1 创建视图
/*1. 为 instructor 创建职员视图 faculty*/
CREATE VIEW faculty
AS
(
SELECT
    id,
    name,
    dept_name
FROM
    instructor
    );
    
    
/*2. 创建视图,列出Physics系在2009年秋季学期开设的所有课程段,以及每个
课程段在哪栋建筑的哪个房间授课*/
CREATE VIEW physics_fall_2009
AS
SELECT
    course.course_id,
    sec_id,
    building,
    room_number
FROM
    course,
    section
WHERE
      course.course_id = section.course_id
  AND course.dept_name = 'Physics'
  AND section.semester = 'Fall'
  AND section.year = 2009
;

4.2.2 使用视图

/*4.2.2 使用视图*/
/*1.使用视图 physics_fall_2009,找到所有在 2009 年秋季学期在 Watson 大楼
开设的 Physics 课程*/
SELECT
    course_id
FROM
    physics_fall_2009
WHERE
    building = 'Watson'
;


/*2.在视图 physics_fall_2009 的基础上,定义视图 physics_fall_2009_Waston */
CREATE VIEW physics_fall_2009_watson
AS
SELECT
    course_id,
    room_number
FROM
    physics_fall_2009
WHERE
    building='Watson'
;

4.2.3 视图的更新

  • 最终会反映到基本表中
  • 视图是不实际存储数据的虚表。因此对视图的更新,最终要转换为对基本表的更新。因为有些视图的更新不能唯一有意义地的装换成对应基本表的更新
  • 不可更新的视图举例
    • 若视图是由两个以上基本表导出的,则此视图不允许更新
    • 若视图的字段来自字段表达式或常数,则不允许对此视图执行INSERT和UPDATE操作,但允许执行DELETE
    • 若视图字段来自聚集函数,则此视图不允许更新
    • 若视图定义中含有GROUP BY 子句,则此视图不允许更新
    • 若视图中含有DISTINCT语句,则此视图不允许更新
    • 若视图定义中含有嵌套查询,并且内层查询的FROM子句涉及的表也是导出该视图的基本表,则此视图不允许更新
    • 一个不允许更新的视图上定义的视图也不允许更新
-- 4.2.3 视图的更新
# 最终会反映到基本表中
/*1.往视图 faculty 中插入一条记录,实际变化反映在表 instructors 中*/
INSERT INTO faculty
VALUES ('30675','Green','Music');

/*2.创建视图 instructor_info,然后插入一条记录,提示不能成功执行*/
CREATE VIEW instructor_info
AS
SELECT
    id,
    name,
    building
FROM
    instructor,
    department
WHERE instructor.dept_name=department.dept_name
;

INSERT INTO instructor_info
VALUES ('69987','White','Taylor');
/*

4.2.4 WITH CHECK OPTION

/*
4.2.5 with check option 命令的作用
 (1)不使用 with check option
创建一个 History 系的教师视图,不使用 with check option
 */
CREATE VIEW history_instructors
AS
    SELECT *
    FROM instructor
    WHERE dept_name = 'history';
    
-- 通过该视图可以插入一条 Biology 系的教师记录
INSERT INTO history_instructors
VALUES ('25566','Brown','Biology',100000);

-- 然后对该视图进行查询,却查找不到刚才插入的这条记录
SELECT *
FROM history_instructors;

但是实际应用中,希望通过哪个视图插入进去的记录,应该也可以通过该 视图查询出来;即某个特定的视图只负责满足特定条件的记录的更新和查询, 不满足特定条件的记录是不能通过该视图更新到基本表的。这时就可以使用 WITH CHECK OPTION 命令

# (2)使用 with check option
# 创建一个 History 系的教师视图
CREATE VIEW history_instructors AS
SELECT *
FROM
    instructor
WHERE
    dept_name = 'History'
WITH CHECK OPTION;

# 通过该视图插入一条 Biology 系的教师记录
INSERT INTO
    history_instructors
VALUES
    ('25566', 'Brown', 'Biology', 100000)
  • 系统提示错误,因为要插入的记录不满足 where dept_name= 'History' 的条件;

  • 所以:定义视图时加上了 WITH CHECK OPTION 子句,对该视图进行插入、修改和删除操作时,DBMS 会自动加上 dept_name= 'History' 的条件

4.4 权限管理

  • 数据安全管理 → \to 安全认证的一个重要指标 (D1, D2, C2, B1,A1)
  1. 用户/密码 → \to 合法用户 → \to 登录到数据库服务器
  2. 能访问到哪一个数据对象 (服务器, 数据库, 数据表, 字段)
  3. 能做什么操作 CRUD
  • 实现步骤
  1. 创建一个用户账号, 密码 (有创建用户权限的账号, 才能发出命令)

    • mysql 系统管理员账号: root (PS: sqlserver sa)

    • 默认情况下, root 账号不允许远程登陆

    • 命令格式:

      Create user ‘用户名’@‘主机名’identified by ‘密码’; 
      
      -- e.g. 
      -- mysql 8.0
      create user 's1'@'localhost' identified by 's1';Create user 's1'@'localhost' identified with mysql_native_password by123; 
      -- mysql8.0
      
      flush privilege; -- 刷新权限
      
  2. 授权: 指定用户能对哪些数据对象做什么样的操作

注意: 此功能已经在实际开发中外移到程序实现

  • 权限管理的框架 RBAC (java shiro)

Chapter 5 Advanced SQL

5.1 函数和存储过程

  • 函数:事先定义,完成一定功能,调用
  • 存储过程:事先定义,完成一定功能,调用

区别

  • 函数一定要有返回值,存储过程不用
  • 函数只能在 DBMS 调用,存储过程可以在 DBMS 和应用程序中调用存储过程名(java)
    • 早期:将重要的业务逻辑用存储过程的方式实现(传输的数据小,并且更加安全)

5.2 触发器

  • 不会作为系统实现的主要方式
  • DBMS主动的去执行一些任务
  • 维护数据库的数据完整性
    • 实体,参照,用户自定义(本表,两个表)
    • 整个数据库中,几个表之间更加复杂的数据完整性委会
    • e.g. A表更新操作 → \to B 表更新操作 → \to C表更新操作

Chapter 6 Formal Relational Query Languages

理论上研究:关系模型要素(数据操作)

要掌握的内容

  • 关系代数的运算特点
    • 运算对象和运算结果都是关系表(一个集合)
  • 关系代数的6个基本运算
    • 每种运算的特点、作用和命令格式
  • 关系代数的附加运算和扩展运算
    • 每种运算的特点、作用和命令格式

6.1 Relational Algebra

6.1.1 Six fundamental operators

6.1.1.1 The Select Operation

select σ \sigma σ

Define as
σ p ( r ) = { t ∣ t ∈ r   a n d   p ( t ) } \sigma_{p}(r)=\{t|t\in r\ and \ p(t) \} σp(r)={ttr and p(t)}

其中, p ( t ) p(t) p(t) 是谓词,表示属性名,是一个筛选条件

e . g .   σ d e p t _ n a m e = " P h y s i c s " e.g.\ \sigma_{dept\_name}="Physics" e.g. σdept_name="Physics"

  • 是一元运算
  • 从行/元组中的角度进行运算
6.1.1.2 The Project Operation

project ∏ \prod

投影操作,取出几列属性

注意:

  • 在关系代数中,如果查询结果出现重复记录,去重复
  • DBMS 中,去重的代价太高,不会自动去重
  • 是一元运算
6.1.1.3 The Union Operation

union ∪ \cup

  • 把两个表的记录合并为一个表
  • 合并的两个表必须要相容
    • 两个合并的表的属性要相同
    • 两个合并的表的数据类型(域)要相同
  • 实际的查询和复杂,分步先实现查询子句,再通过并运算合并查询
  • 在关系代数中:并操作需要去重
  • 是二元运算
6.1.1.4 The Set-Difference Operation

set difference r − s r-s rs

Define as
r − s = { t ∣   t ∈ r   a n d   t ∉ s } r-s=\{t|\ t\in r \ and \ t \notin s \} rs={t tr and t/s}

  • 差运算也需要满足相容规则
6.1.1.5 The Cartesian-Product Operation

caetesian product × \times ×

Define as
r × s = { t , q ∣   t ∈ r   a n d   q ∈ s } r\times s =\{t,q|\ t\in r\ and \ q \in s \} r×s={t,q tr and qs}

  • 产生一个大表,属性是两表相加,记录个数是两表相乘
  • 笛卡尔积运算的意义
    • 将分布在多个表中的数据连接起来,做成一个表(多表查询、连接查询)
      • e.g. 查询需求分布在两个表中,所以要先构造一个包含两个表信息的新表,再根据筛选条件筛选信息
    • 一定要对结果进行进一步的做运算,这样才能获得正确的数据
  • 如果有相同的属性,前面加上表名
  • 进行笛卡尔积运算的两个表,可以是相同的表,也可以是不同的表,但是属性个数不一定要相等

e.g. 如果两个表中都有 id 这个属性,他们笛卡尔积的属性如下

teacher.id
course.id
6.1.1.7 The Rename Operation
  • 给一个表重命名:简化表名、表和表自连接时,需要对表重命名给一个属性重命名:简化属性名

  • 对一个属性进行了函数/运算后起名

  • 属性英文名 → \to 改为中文名

6.1.3 Additional Relational-Algebra Operations

6.1.3.1 The Set-Intersection Operation

r   ∩   s = r − ( r − s ) r\ \cap \ s=r-(r-s) r  s=r(rs)

6.1.3.2 The Natural-Join Operation

Π name, course-id   (instructor  ⋈  teaches)  \Pi_{\text {name, course-id }} \text { (instructor } \bowtie \text { teaches) } Πname, course-id  (instructor  teaches) 

  • 自动去除相同的属性,直接提取出正确的记录

  • 包含三种运算:笛卡尔积运算、选择运算、投影

  • 自然连接是可交换和可结合的

  • 如果做自然连接,一定要存在同名且相同数据类型的属性(相同的至少一列字段)

6.1.3.3 The Assignment Operation

赋值运算的定义:当查询和复杂时,分步完成时得到了一些中间结果,再通过赋值运算,用临时表的形式保存下来(复杂的查询任务)

e.g.

t e m p 1 ← R × S temp1 ← R × S temp1R×S
t e m p 2 ← σ . A 1 = s . A 1 ∧ r . A 2 = s . A 2 ∧ . . . ∧ r . A n = s . A n ( t e m p 1 ) temp2 ← \sigma.A_1 = s.A_1 ∧r.A_2 = s.A_2 ∧ ... ∧r.A_n = s.A_n (temp1) temp2σ.A1=s.A1r.A2=s.A2...r.An=s.An(temp1)
r e s u l t = ∏ R ∪ S ( t e m p 2 ) result = \prod _{R ∪ S} (temp2) result=RS(temp2)

6.1.3.4 Outer join Operations

e.g. 此图产生了空值,表示有些老师没有上课信息

PS:如果做自然连接,就不包含没有上课的老师的信息(不匹配)

image-20210319094424382

  • 左外连接:全部显示左表数据
  • 右外连接:全部显示右表数据
  • 如果匹配显示匹配值,不匹配显示 n u l l null null
6.1.3.5 Generalized Projection
6.1.3.5 Aggregation

聚集函数,返回的是一个值
G p ( x ) ( k e y ) ( t a b l e ) G_{p(x)(key)}(table) Gp(x)(key)(table)
P ( x ) P(x) P(x) 有以下几种

  • count 查询结果中记录的个数
  • avg
  • maxmin
  • sum

分组和聚集函数常常搭配使用
k e y 1 G p ( x ) ( k e y 2 ) key_1G_{p(x)(key_2)} key1Gp(x)(key2)
对坐标进行以下命令得到右表
d e p t _ n a m e G a v g ( s a l a r y ) ( i n s t r u c t o r ) dept\_nameG_{avg(salary)}{(instructor)} dept_nameGavg(salary)(instructor)
image-20210325103634437

Chapter 7 Database Design and the E-R Model

  1. 设计目的:消除一切冗余

  2. 设计三要素

  • 确定实体集
  • 辨别实体集之间的联系
  • 确定联系的类型
  • 确定实体集和联系的属性
  • 确定属性的类型

7.3 Constraints

7.3.1 Mapping Cardinalities 映射的势(基数)

描述一个实体通过联系集对应另一个实体的个数

联系的类型

  • 1对1(大学 → \to 校长)

  • 1对多 (宿舍 → \to 学生)

  • 多对多 (学生 → \to 选课)

image-20210514083559609

image-20210514083615151

7.3.2 Participation Constraints 参与约束

  • 实体集参与到联系里时是全部参与还是部分参与
    • 全部参与 → \to 外码字段不能为空
    • 部分参与 → \to 外码字段可以为空
    • 帮助我们判断两个实体集之间的联系是否合适(如果出现大量空值,则定义的联系不合适)
  • 一个表的记录是否完全参与到另一个表中
  • 间接联系(具有传递性的联系)可以不用写

For example, we expect every student entity to be related to at least one instructor through the advisor relationship. Therefore the participation of student in the relationship set advisor is total. In contrast, an instructor need not advise any students. Hence, it is possible that only some of the instructor entities are related to the student entity set through the advisor relationship, and the participation of instructor in the advisor relationship set is therefore partial.

7.3.3 Keys

主码约束:对每一个实体集都要确定一个主码

7.6 Reduction to Relational Schemas

7.6.1 Representation of Strong Entity Sets with Simple Attributes 简单属性的强实体集转换

简单属性的强实体集转换

简单属性:只有一个值

强实体集:有主码

7.6.2 Representation of Strong Entity Sets with Complex Attributes 复杂属性的强实体集转换

复杂属性的强实体集转换

  • 复杂属性
    • 复合属性:有多个子属性的属性
      • 在转换时候拉平,写出所有属性
      • e . g   n a m e → n a m e . f i s r t _ n a m e , n a m e . l a s t _ n a m e e.g \ name \to name.fisrt\_{name},name.last\_{name} e.g namename.fisrt_name,name.last_name
    • 多值属性
      • 通过主码映射构建新表,单独生成新表
      • e . g .   i n s t ( i d , s a l a r y , . . . ) , i n s t _ p h o n e ( i d , p h o n e _ n u m b e r ) e.g.\ inst(id,salary,...),inst\_phone(id,phone\_number) e.g. inst(id,salary,...),inst_phone(id,phone_number)
    • 派生属性
      • 派生字段:由计算得出,可以删除也可以保留
      • 删除:消除冗余
      • 保留:提高查询速度,便于建立索引(因为对表做算数处理之后索引失效)
      • e . g .   s t u ( i d , b i r t h , a g e )    a g e e.g.\ stu(id,birth,age)\ \ age e.g. stu(id,birth,age)  age 就是 b i r t h birth birth 的派生属性

强实体集:有主码

7.6.3 Representation of Weak Entity Sets 弱实体集转换

一般较少出现,依赖于强实体集,借依赖的强实体集的主码和自己的属性

e . g . s e c t i o n ( c o u r s e _ i d , s e c _ i d , s e m e s t e r , y e a r ) e.g. section(course\_id,sec\_id,semester,year) e.g.section(course_id,sec_id,semester,year)

7.6.4 Representation of Relationship Sets 联系集转换

  • 关系模式:联系集本身
  • 属性:参与联系的实体集的主码

1:1 联系的主码

  • 涉及到联系集的两端的主码属性和联系集本身的属性
  • 任一方的实体集的主码

1:n 联系的主码

  • 使用最精确的做主码

m:n 联系的主码

  • 使用联系集的两端的主码同时做主码
7.6.4.1 Redundancy of Schemas
  • 合并主码相同的表(1对1,1对多)
    • 注意:多对多的表不可合并

7.7 Entity-Relationship Design Issues

  1. 数据库设计三要素
  • 实体集
  • 联系集
  • 属性
  1. 建立信息模型 → \to ER 模型
  • 三要素在 ER 图中全部都要体现出来
  1. ER 模型 → \to 数据模型转换(关系模型,对象模型,非关系型数据库模型)

注意:ER 图的所有要素都要转换成关系模式

  • 实体集 → \to 关系模式

7.7.1 Basic Structure

image-20210514092511430

  • 矩形:实体集
  • 菱形:表示联系,在联系中心写联系的名字
  • 菱形加虚线矩形:联系的属性
  • 两个实体集之间用
    • 箭头连接:一
    • 不用箭头连接:多(有箭头的那方)
  • 全部参与:双线
  • 对于较复杂的符合属性:使用缩进
  • 多值属性:使用大括号 phone_number
  • 派生属性:使用括号 age()
  • 双菱形加虚下划线:不具有主码的实体集为弱实体集,强实体集:有主码
    • 一个弱实体集不能独立存在,要依赖于强实体集存在

7.9 Alternative Notations for Modeling Data

7.9.1 Symbols used in the E-R notation

image-20210527224340762

Chapter 8 Relational Database Design

8.1 Features of Good Relational Designs

  • 使用规范化理论,衡量或者评估或改进工具进行数据库优化

    • 通过对关系模式的分解解决不合适的数据依赖(通过对低级别范式的优化,表的分解,在规范化的过程中,一个表会被优化为多个表)
    • 范式:normal form (NF)
    • 多级范式:第一到第三范式( 1 ∼ 3 1\sim 3 13 NF),BC 范式 (BCNF),第四到五范式( 4 ∼ 5 4\sim 5 45 NF)
      • 范式级别越低,表示约束的标准越低,越宽松,级别太低的表是不可用的,需要提高其范式
      • 一个关系模式的范式定义为:$R\in nNF\ \ e.g.student\in 3NF $
      • 在设计数据库时,范式级别往往呗指定为数据库工程的验收标准
  • 前提:系统分析 → \to ER 模型能够比较好的贴近现实问题 → \to 转换关系表 → \to 表的质量较好(紧密围绕某一个主题去确定属性)

  • 纯粹从理论上提出的一套规范化的方法 (有些方法在现实中无法使用)

    • 基本前提:泛关系假设(假设开始设计数据库的时候,一个数据库中的多个表的属性是合在一个表中的)
      • 大表的质量肯定比较差 → \to 对这个大表使用规范化理论进行优化
      • 构成大表的原因是实体集找的不好,但是如果全部确认了比较好的实体集,这章屁用没有,常会出现的错误是实体集的属性找的不好
  • 优化的目的:消除冗余

  • 把多个主题的属性合并到一个表中

    • 优点:方便查询
    • 缺点
      • 浪费存储空间,数据冗余情况严重
      • 更新数据的操作要更新所有相关数据,导致更新操作相对困难
      • 扩展了主码,需要更加详细的字段信息
    • 产生问题的原因:数据之间的依赖关系

8.2 Atomic Domains and First Normal Form (1NF)

  • 所有字段是原子(不可分解的),不存在复合属性
  • 级别最低,对关系表的要求最低
  • 避免:有一些看着是原子,但是实际上可以分割的字段,需要消除,不要使用程序解读

8.3 Decomposition Using Functional Dependencies (3NF & BCNF)

8.3.1 Functional Dependencies

  • 函数依赖(FD):研究两组属性集之间的依赖关系(两个属性谁决定谁、唯一决定)
    • 简明定义: x → f ( x ) = { d 1 , d 2 , . . . , d n } x\to f(x)=\{d_1,d_2,...,d_n\} xf(x)={d1,d2,...,dn},例如 f ( i d ) = { n a m e , d e p t _ n a m e , s a l a r y } f(id)=\{name,dept\_name,salary\} f(id)={name,dept_name,salary}
    • 严谨定义:Consider a relation schema r ( R ) r(R) r(R), and let α ⊆ R \alpha \subseteq R αR and β ⊆ R \beta \subseteq R βR
      • Given an instance of r ( R ) r(R) r(R), we say that the instance satisfies the functional dependency α → β \alpha \rightarrow \beta αβ if for all pairs of tuples t 1 t_{1} t1 and t 2 t_{2} t2 in the instance such that t 1 [ α ] = t 2 [ α ] t_{1}[\alpha]=t_{2}[\alpha] t1[α]=t2[α], it is also the case that t 1 [ β ] = t 2 [ β ] t_{1}[\beta]=t_{2}[\beta] t1[β]=t2[β]
      • We say that the functional dependency α → β \alpha \rightarrow \beta αβ holds on schema r ( R ) r(R) r(R) if, in every legal instance of r ( R ) r(R) r(R) it satisfies the functional dependency.
      • [ α ] [\alpha] [α] 表示在 α \alpha α 上的取值
    • 从函数依赖的角度可以定义码
      • K K K is a superkey of r ( R ) r(R) r(R) if the functional dependency K → R K \rightarrow R KR holds on r ( R ) . r(R) . r(R).
      • K K K is a candidate key for R R R if and only if K → R K\to R KR and for no a ⊆ K , K → R a\subseteq K , K\to R aK,KR
    • 关系表中的属性类型
      • 主码属性
      • 非主码属性
      • 候选码属性
  • 函数依赖的集合: F F F 表示若干个在 R R R 上成立的 FD 的集合
  • 刻画一个关系模式 R R R
    • 属性: R ( A 1 , A 2 , . . . A n ) R(A_1,A_2,...A_n) R(A1,A2,...An)
    • 函数依赖关系: F = { A 1 → A 2 . . . } F=\{A_1\to A_2...\} F={A1A2...}
  • 函数依赖的类型
    • 平凡的函数依赖
      • a functional dependency of the form α → β \alpha \rightarrow \beta αβ is trivial if β ⊆ α \beta \subseteq \alpha βα
      • 自己决定自己,在任何 R R R 上,任何属性上都成立
      • 例如, A B → A AB\to A ABA 就是一个平凡的函数依赖,因为 { A } ⊆ { A B } \{A\} \subseteq \{AB\} {A}{AB}
      • 表明了属性和属性自己是有关系的
    • 传递函数依赖(不好的)
      • A → B , B → C A\to B, B\to C AB,BC
    • 完全函数依赖(好的)
      • 一个完全函数依赖成立,当且仅当 X 1 , X 2 → Y X_1,X_2\to Y X1,X2Y 成立,且 X 1 → Y , X 2 → Y X_1\to Y,X_2\to Y X1Y,X2Y 不成立
      • 也就是说, Y Y Y 要完全依赖于 X 1 , X 2 X_1,X_2 X1,X2 的值,没有多余的属性
    • 部分函数依赖(不好的)
      • 一个部分函数依赖成立,当且仅当 X 1 , X 2 → Y X_1,X_2\to Y X1,X2Y 成立,且 X 1 → Y , X 2 → Y X_1\to Y,X_2\to Y X1Y,X2Y 也成立
      • 也就是说, Y Y Y 部分依赖于 X 1 , X 2 X_1,X_2 X1,X2 的值,只要 X 1 , X 2 X_1,X_2 X1,X2 的一部分知道, Y Y Y 就成立
  • 函数依赖的闭包
    • R R R 上成立的所有的 FD 的集合
  • 堆到规则

8.3.2 Boyce-Codd Normal Form !!

  • 定义(重点):A relation schema R R R is in BCNF with respect to a set F F F of functional dependencies if, for all functional dependencies in F + F^{+} F+ of the form α → β \alpha \rightarrow \beta αβ, where α ⊆ R \alpha \subseteq R αR and β ⊆ R \beta \subseteq R βR, at least one of the following holds:
    • α → β \alpha \rightarrow \beta αβ is a trivial functional dependency (that is, β ⊆ α ) \beta \subseteq \alpha) βα).
    • α \alpha α is a superkey for schema R R R.

这个定义是一个判断标准

  • 对于 F + F^{+} F+所有形如 α → β \alpha \rightarrow \beta αβ 的函数依赖(也就是所有的函数依赖,如 { a → b , b → c , a b → d e } \{a\to b, b\to c, ab\to de\} {ab,bc,abde}),如果满足其中其中之一的条件,则为 BCNF
    • 判断 α → β \alpha \rightarrow \beta αβ 是不是平凡的 FD
    • 判断 α → β \alpha \rightarrow \beta αβ α \alpha α 是不是超码

总结:在 R R R 上,能够存在的函数依赖,要么是平凡的函数依赖,要么 α \alpha α (决定因素)是超码,则 R ⊆ R \subseteq R BCNF. 也就是说发出箭头的除平凡外就是超码

8.3.3 BCNF and Dependency Preservation

如果一个关系 R R R not in BCNF → \to 优化(模式分解) → \to 成为许多小的关系模式 { R 1 , R 2 , . . . , R n } \{R_1,R_2,...,R_n\} {R1,R2,...,Rn}

把一个 R R R 分解为若干个子关系模式时,达到 BCNF 要求时,有可能会丢失一些函数依赖(不保持函数依赖)

分解需要满足两个前提条件

  • 分解之后要保持函数依赖

8.3.4 Third Normal Form

A relation schema R R R is in third normal form with respect to a set F F F of functional dependencies if, for all functional dependencies in F + F^{+} F+ of the form α → β \alpha \rightarrow \beta αβ, where α ⊆ R \alpha \subseteq R αR and β ⊆ R \beta \subseteq R βR, at least one of the following holds:

  • α → β \alpha \rightarrow \beta αβ is a trivial functional dependency.
  • α \alpha α is a superkey for R R R.
  • Each attribute A A A in β − α \beta-\alpha βα is contained in a candidate key for R R R.
    • β − α \beta-\alpha βα:它们的差
    • A A A :主属性(构成候选码的属性)
    • 是不是由主属性构成的

Note that the third condition above does not say that a single candidate key must contain all the attributes in β − α ; \beta-\alpha ; βα; each attribute A A A in β − α \beta-\alpha βα may be contained in a different candidate key.

8.3.5 Second Normal Form

如果关系 R ∈ R \in R 1NF,并且 R R R 中的每一个非主属性完全依赖于主关键字

8.4 Functional-Dependency Theory

  • 函数依赖在当前这个表上对不对
  • 候选码的确认

8.4.1 Closure of a Set of Functional Dependencies

  • logically implied:Given a set F F F of functional dependencies on a schema, wecan prove that certain other functional dependencies also hold on the schema. We say that such functional dependencies are “logically implied” by F F F.

已知: R ( A 1 , A 2 , A 3 , A 4 ) , F = { A 1 → A 2 , A 1 → A 3 } R(A_1,A_2,A_3,A_4), F=\{A_1\to A_2,A_1\to A_3\} R(A1,A2,A3,A4),F={A1A2A1A3}

问:在 R R R 上,还有没有一些未知的 FD 能够基于已知的 F F F 推导出来,如何证明?

  • Armstrong’s axioms:作为工具来回答以上问题

    • 三条公理

      • Reflexivity rule. If α \alpha α is a set of attributes and β ⊆ α \beta \subseteq \alpha βα, then α → β \alpha \rightarrow \beta αβ holds.
      • Augmentation rule. If α → β \alpha \rightarrow \beta αβ holds and γ \gamma γ is a set of attributes, then γ α → γ β \gamma \alpha \rightarrow \gamma \beta γαγβ holds.
      • Transitivity rule. If α → β \alpha \rightarrow \beta αβ holds and β → γ \beta \rightarrow \gamma βγ holds, then α → γ \alpha \rightarrow \gamma αγ holds.
    • 三条公理的性质

      • 正确性:基于这三个推导规则推导出的结果
      • 完备性:利用此三个推导规则,能够把所有的函数依赖都能证明
    • 三条派生规则

      • Union rule. If α → β \alpha \rightarrow \beta αβ holds and α → γ \alpha \rightarrow \gamma αγ holds, then α → β γ \alpha \rightarrow \beta \gamma αβγ holds.
      • Decomposition rule. If α → β γ \alpha \rightarrow \beta \gamma αβγ holds, then α → β \alpha \rightarrow \beta αβ holds and α → γ \alpha \rightarrow \gamma αγ holds.
      • Pseudotransitivity rule. If α → β \alpha \rightarrow \beta αβ holds and γ β → δ \gamma \beta \rightarrow \delta γβδ holds, then α γ → δ \alpha \gamma \rightarrow \delta αγδ holds.
    • 六个推导规则的作用

      • 求给定关系模式的码 K → R K\to R KR
      • 计算 F + F^+ F+ (有一些算法)
      • 求一组函数依赖中蕴含的函数依赖
    • 求一组函数依赖中蕴含的函数依赖

      • 利用 Armstrong 公理系统直接证明(困难)

      • 计算 F + F^+ F+ 看当前的函数依赖是否处于闭包中(困难)

      • 求出 α \alpha α 属性集闭包,判断 α → β \alpha \rightarrow \beta αβ (容易:属性的个数是有限的)

        属性集闭包 α \alpha α 能决定的所有属性

        如,判断 α → β 1 \alpha \rightarrow \beta_1 αβ1 F F F 上成立,求出 α \alpha α 属性集闭包 ( β 1 , β 2 , β 3 ) (\beta_1,\beta_2,\beta_3) (β1,β2,β3)

  • 属性集闭包的作用

    • 判断 PD 的逻辑蕴含关系
    • 判断一个属性集是否为超码:一个属性集的闭包等于所有的属性,它就是超码
    • 判断一个属性集是否为候选码(超码的最小化):首先为超码,并且作为超码有没有多余属性
      • A+=R A A A 自己就可以决定所有的属性, A A A 就是候选码, B B B 是多余的
      • A+= ACB​ 且 B+=AGCD ( R = A B C D G ) (R = ABCDG) (R=ABCDG) → \to A B AB AB 没有多余的属性, A B AB AB是候选码
      • 在经典的数据库设计中,不能随意添加 ID 字段,但是在现在的实际应用中,经常认为添加 ID 属性

8.4.2 Canonical Cover 正则覆盖/最小覆盖

已知一个 F F F (函数依赖),将 F F F 最小化,得到 F c / F m i n F_c/F_{min} Fc/Fmin (正则覆盖)

  • 正则覆盖的作用

    • 在进行模式分解时,消除多余的函数依赖,使得最终建表精简
    • 在 DBMS 中真正建立数据表的时候,FD ,约束表现
  • F F F 最小化:消除冗余的 FD

    • F F F 中,有相同的 FD 去除

    • F F F 中,有一些 FD 可以被其他的 FD 直接推导 (传递,自反,合并,分解)

    • 复合属性(extraneous attributes):有没有多余属性

      • 左边为复合属性: e . g .   A B → C e.g. \ AB\to C e.g. ABC A B AB AB 中是否有多余属性

        Attribute A A A is extraneous in β \beta β if A ∈ β A \in \beta Aβ, and the set of functional dependencies ( F − { α → β } ) ∪ { α → ( β − A ) } (F-\{\alpha \rightarrow \beta\}) \cup\{\alpha \rightarrow(\beta-A)\} (F{αβ}){α(βA)} logically implies F . F . F.

        假设 A A A 是多余的,去掉旧的 FD (含有 A A A),加上新的 FD (去掉了 A A A),得到新的 F ′ F' F

      • 右边为复合属性: e . g .   A → B C e.g. \ A\to BC e.g. ABC B C BC BC 中是否有多余属性

        Attribute A A A is extraneous in α \alpha α if A ∈ α A \in \alpha Aα, and F F F logically implies ( F − { α → β } ) ∪ { ( α − A ) → β } . (F-\{\alpha \rightarrow\beta\}) \cup\{(\alpha-A) \rightarrow \beta\} . (F{αβ}){(αA)β}.

      • 需要证明

    • 正则覆盖Notice

      • 判断左边的复合属性,直接在原本的依赖集中求闭包
        比如有 A B → C AB \to C ABC ,如果想去掉 A A A 或者 B B B,就看看函数依赖集中的 A + A^+ A+ A A A 的闭包) 或者 B + B^+ B+ 中有没有 C C C 即可,因为如果 B B B 能够从它单独的自己出发推出 C C C 那么 A A A 在这个关系中就是无用的
      • 判断右边的复合属性,才需要把函数依赖中的元素删掉再放回原函数依赖集

8.4.3 候选码的确定

关系 R ( U , F ) R(U,F) R(U,F) 中,假定 F F F 已经是最小覆盖

  • 准则 1 1 1:如果属性 A A A 只在 F F F 中各函数依赖的左端出现或根本没有出现过,则 A A A 一定是候选码中的属性
  • 准则 2 2 2:如果属性 A A A 只在 F F F 中各函数依赖的右端出现,则 A A A 一定不是候选码中的属性

确定候选码的步骤是
(1) 对于关系模式 R ( U , F ) R(U,F) R(U,F),求 F F F 的最小覆盖,仍用 F F F 表示
(2) 根据准则 1 1 1,确定候选码中必须有的属性集(设为 M M M)
(3) 根据准则 2 2 2,去掉候选码中没有的属性集(设为 G G G)
(4) 确定余下的属性集(设为 W W W)。
(5) 从 M M M 开始,令 K = M K=M KM,如果 K F + = U K_F^+=U KF+=U U U U 为全集), K K K 就是候选码。否则从 W W W 选择属性加入到 K K K 中,直到 K F + = U K_F^+=U KF+=U K K K 就是候选码
(6) 注意:可能有多个候选码

8.4.4 无损连接和保持函数依赖

  • 对于 R ( U , F ) \mathrm{R}(\mathrm{U}, \mathrm{F}) R(U,F) 的一个分解 ρ = { R 1 , R 2 } \rho=\left\{R_{1}, R_{2}\right\} ρ={R1,R2} ,如果 R 1 ∩ R 2 → R 1 ∈ F + R_{1} \cap R_{2} \rightarrow R_{1} \in F^{+} R1R2R1F+ R 1 ∩ R 2 → R 2 ∈ F + R_{1} \cap R_{2} \rightarrow R_{2} \in F^{+} R1R2R2F+, 则该分解具有无损连接性
  • F + = ( ⋃ i = 1 k F i ) + F^{+}=\left(\bigcup_{i=1}^{k} F_{i}\right)^{+} F+=(i=1kFi)+, 则 R ( U , F ) \mathrm{R}(\mathrm{U}, \mathrm{F}) R(U,F) 的分解 ρ = { R 1 < U 1 , F 1 > , ⋯   , R k < U k , F k > } \rho=\left\{R_{1}<U_{1}, F_{1}>, \cdots, R_{k}<U_{k}, F_{k}>\right\} ρ={R1<U1,F1>,,Rk<Uk,Fk>} 保持函数依赖

8.4.5 关系模式 R R R 的优化 模式分解

  • F F F 的最小集要求出来

  • 候选码要求出来

  • 判断 R R R 的范式级别

  • 模式分解:分解的两个前提条件

    • 无损分解(第一要保证,一定要保证):数据的正确性,记录数要等于分解之后子表连接运算的记录数
    • 保持函数依赖(第二要保证):分解后所有的函数依赖的并等于原函数依赖
  • BCNF 分解算法(满足无损分解)

    • 至少有一个函数依赖不满足 BCNF 的要求时就执行优化

image-20210603112734028

  • 3NF 分解算法(满足无损分解和保持函数依赖)
    • 先算最小覆盖 F c F_c Fc
    • 找出候选码
    • 根据 F c F_c Fc 中的函数依赖分解
      • 一个函数依赖就生成一个子表 T n = { . . . } T_n=\{...\} Tn={...}
      • C o u n t ( T n ) = C o u n t ( F c ) Count(T_n)=Count(F_c) Count(Tn)=Count(Fc)
    • 检查候选码 K K K 是否包含在某个子表中
      • 包含: T n = { . . . } T_n=\{...\} Tn={...} 就是结果, C o u n t ( T n ) = C o u n t ( F c ) Count(T_n)=Count(F_c) Count(Tn)=Count(Fc)
      • 不包含:将候选码 K K K 生成一个子表, C o u n t ( T n ) = C o u n t ( F c ) + 1 Count(T_n)=Count(F_c)+1 Count(Tn)=Count(Fc)+1

Chapter11 Indexing and Hashing

SQL 查询语句十分重要

  • 构造 SQL: 怎么样写出质量高的 SQL 语句
  • 运行期间: 查询语句 → \to 执行慢 → \to 观察分析 SQL

11.1 索引 Index

提高查询速度的有效办法

是帮助 MySQL 高效获取数据的数据结构(有序)。即在数据之外,数据库系统还维护着满足特定查找算法的数据结构,这些数据结构以 某种方式引用(指向)数据,这样就可以在这些数据结构上实现高级查找算法,这种数据结构就是索引

  • 索引的作用:快速查找数据

当表中有大量记录时,若要对表进行查询,第一种搜索信息方式是全表搜索, 是将所有记录一一取出,和查询条件进行一一对比,然后返回满足条件的记录,这样做会消耗大量数据库系统时间,并造成大量磁盘 I/O 操作;第二种就是在表中建立索引,然后在索引中找到符合查询条件的索引值,最后通过保存在索引中 的 ROWID(相当于页码)快速找到表中对应的记录

  • 索引的缺点
    • 要占用额外的存储空间
    • 降低更新表的速度:更新表时,MySQL 不仅要保存数据,还有可能要维护索引文件

11.1.1 索引的分类

  • 聚簇索引
    • 索引中键值的逻辑顺序决定了表中相应记录的物理顺序
    • 主键索引(等价于基本表):在主码字段上建立的索引
  • 非聚簇索引
    • 单列索引:一个索引只包含单个列,一个表可以有多个单列索引
    • 唯一索引:索引列的值必须唯一,但允许有空值
    • 复合索引:一个索引包括多个列
    • 全文索引:在 MyISAM 引擎支持,只能在 CHAR,VARCHAR,TEXT 类型字段上使用

11.1.2 索引的创建和删除

  • 主键索引:DBMS 自动创建 (在表上定义了主键时,会自动创建一个主键索引)

  • 单列属性索引:一个表可以有多个单列索引

CREATE INDEX name_index ON student(NAME); 

此外,在表上定义一个外键时,会自动创建一个普通索引

  • 唯一索引:相应属性的值不能重复
CREATE UNIQUE INDEX title_index ON course(title);
  • 复合索引:多个属性一起构成的索引
CREATE INDEX dept_name_index ON student(dept_name,name); 

11.1.3 索引的维护

  • 删除索引:DROP INDEX 索引名 ON 表名;
DROP INDEX name_index ON tb;
  • 查询表上建立的索引:SHOW INDEX FROM 表名;
SHOW INDEX FROM student; 

11.1.4 索引的选择

使用索引也是有代价的,因为索引本身要占用存储空间,同时索引会加重更新记录时的负担,因此所引并不是越多越好

  • 适合创建索引的字段

    • 主码和外码字段
    • Where 子句中的常用到的查询条件的字段
    • 查询中与其他表关联的字段,
    • 排序的字段,统计或分组的字段创建索引
  • 不适合创建索引的字段

    • 频繁更新的字段不适合建立索引
    • Where 条件用不到的字段,不创建索引
    • 表中记录较少时,不需要建立索引
    • 经常增删改的表不要建立索引
    • 重复值多的字段不要建立索引

    计算字段不重复的比例

    SELECT
        COUNT(DISTINCT (dept_name)) / COUNT(*) AS Selectivity
    FROM
        instructor;
    

11.1.5 InnoDB 中的主键索引

MySQL InnoDB 数据存储结构 (hellopz.com)

InnoDB 的页结构

InnoDB 存储引擎将数据划分为若干个页,以页作为磁盘和内存之间交互的 基本单位,页的大小一般为 16KB。因此,InnoDB 一次最少从磁盘中读取 16KB 的内容到内存中;一次最少把内存中的 16KB 内容刷新到磁盘中

  • 每一条记录不能跨页,设计表的时候,字段的数据类型和长度不能

image-20210505125318548

名称中文名占用空间大小简单描述
File Header文件头部38字节页的一些通用信息
Page Header页面头部56字节数据页专有的一些信息
Infimum + Supremum最小记录和最大记录26字节两个虚拟的行记录
User Records用户记录不确定实际存储的行记录内容
Free Space空闲空间不确定页中尚未使用的空间
Page Directory页面目录不确定页中的某些记录的相对位置
File Trailer文件尾部8字节校验页是否完整
  • 插入数据时,数据页的变化如下

MySQL存储行

  • 多个页之间采用双向链表连接

img

InnoDB 的记录(行)结构

Mysql 中记录的格式类型包括:Compact、redundant、dynamic、compressed 四种,默认是 compact 行类型

image-20210505131904703

(1)变长字段:

  • 列长度 < 255 字节,用 1 字节表示
  • 列长度 > 255 字节,用 2 字节表示
  • 长度最大不能超过 2 个字节,因为 MySQL 数据库中 VARCHAR 的最大长度限制为 65535

(2)NUll 标志位:

  • 记录该行数据是否有 NULL 值,有就用 1 表示,占 1 个字节;
  • 如果这个行数据有 NULL,则不占任何空间;

(3)记录头信息:

  • 固定占 5 个字节,即 40 位,具体记录头信息见下图

(4)实际的每列的数据

(5)每行数据除了用户定义的列之外,还有两个隐藏列

compact行头信息

名称大小(单位:bit)描述
预留位11没有使用
预留位21没有使用
delete_mask1标记该记录是否被删除
min_rec_mask1B+树的每层非叶子节点中的最小记录都会添加该标记
n_owned4表示当前记录拥有的记录数
heap_no13表示当前记录在记录堆的位置信息
record_type3表示当前记录的类型,0表示普通记录,1表示B+树非叶子节点记录,2表示最小记录,3表示最大记录
next_record16表示下一条记录的相对位置

当对记录进行增删改操作,InnoDB 始终会维护一条记录间的单链表,链表 中的各个节点是按照主键值由小到大的顺序连接起来的

11.1.6 避免索引失效方法

  1. 防止复合索引失效
  • 不要跨列或无序使用(遵循最佳左前缀原则)
  • 尽量使用全索引匹配
  • 不能使用不等于(!= <>)或 is null (is not null),否则自身以及右侧所有索引全部失效
  1. 不要在索引上进行任何操作(计算、函数、类型转换),否则索引失效

如假设 A.x 是索引

不要写成:SELECT ..WHERE A.x*3 = .. ;

  1. like 尽量以“常量”开头,不要以'%'开头,否则索引失效
  • tname 索引失效
EXPLAIN
SELECT *
FROM
    student
WHERE
    name LIKE '%x%'; 
  • 不以’%'开头,name 索引不失效
EXPLAIN
SELECT *
FROM
    student
WHERE
    name LIKE 'x%';
  • 如果必须使用 like '%x%'进行模糊查询,可以将索引列放在 select 后面,使用索引覆盖挽救一部分
EXPLAIN
SELECT
    name
FROM
    student
WHERE
    name LIKE '%x%';

11.2 SQL 语句命令执行分析

查询优化器 → \to SQL 语句进行编译 → \to 生成查询计划(使用的表,索引文件)

11.2.1 EXPLAIN 命令

查看 SQL 的执行计划,模拟 SQL 优化器执行 SQL 语句,可以让开发人员分析 SQL 执行的状况

EXPLAIN 命令可以查看 SQL 语句的执行计划。当 EXPLAIN 与SQL语句一起使用时,Mysql将显示来自优化器的有关语句执行计划的信息。也就是说,Mysql解释了它将如何处理语句,包括有关如何联接表以及以何种顺序联接表的信息

  • EXPLAIN 的作用
    • 分析出表的读取顺序
    • 数据读取操作的操作类型
    • 哪些索引可以使用
    • 哪些索引被实际使用
    • 表之间的引用
    • 每张表有多少行被优化器查询
参数描述
id执行select子句或操作表的顺序
select_type查询的类型,如SIMPLE、PRIMARY、SUBQUERY、DERIVED、UNION等
table当前行使用的表名
partitions匹配的分区
type连接类型,如system、const、eq_ref、ref、range、index、all等
possible_keys可能使用的索引
key实际使用的索引,NULL表示未使用索引
key_len查询中使用的索引长度
ref列与索引的比较
rows扫描的行数
filtered选取的行数占扫描的行数的百分比,理想的结果是100
extra其它额外信息

参数解析

  1. id : 编号
  • id 值相同:表示从上往下顺序执行。表的执行顺序因记录数的改变而改变,记录数少的表优先查询
  • id 值不同:id 值越大越优先查询。如在嵌套子查询时,先查内层再查外层
  1. select_type :查询类型
  • PRIMARY:表示包含子查询 SQL 中的主查询(外层);
  • SUBQUERY:表示包含子查询 SQL 中的子查询 (非最外层);
  • SIMPLE:表示简单查询,不包含子查询、union 查询;
  • DERIVED:表示衍生查询,使用到了临时表;
  1. type:查询时用到的索引类型

主要类型: s y s t e m > c o n s t > e q _ r e f > r e f > r a n g e > i n d e x > a l l system>const>eq\_ref>ref>range>index>all system>const>eq_ref>ref>range>index>all,越往左边性能越高

要对 type 进行优化的前提是要有索引 (systemconst 只是理想情况,实际能达到 refrange 类型)

  • system:只有一条数据的系统表或衍生表只有一条数据的主查询

  • const:仅仅能查到一条数据的 SQL ,用于 primary key 或 unique 索引

  • eq_ref:唯一性索引,对于每个索引键的查询,返回匹配唯一行数据(有且只有 1 个)

  • ref:非唯一性索引,对于每个索引键的查询,返回匹配的所有行

  • range:只检索给定范围的行,使用一个索引来选择行

  • index:使用全文索引

  • ALL:全表扫描

  1. possible_keys :系统预测可能用到的索引

如果 possible_key/keyNULL,则说明该查询没用到索引

  1. key :实际查询时使用到的索引

如果 key 为 NULL,则说明该查询没用到索引

  1. key_len :使用的索引长度

可用于判断复合索引中的属性是否被完全使用

注意:

  • utf8:1 个字符 3 个字节
  • gbk:1 个字符 2 个字节
  • latin:1 个字符 1 个字节
  • 如果索引字段可以为 NULL,则会使用 1 个字节用于标识
  • Varchar:用 2 个字节标识可变长度
  1. ref

注意与 type 中的 ref 值区分

作用:指明当前表所参照的字段

  1. rows: 记录个数

  2. extra:额外信息

using filesort:表示该 SQL 语句性能消耗大,需要“额外”的一次排序(查询),常见于 order by 语句中,如:

  • 对于单索引

    • 如果排序和查找是同一个字段,则不会出现 using filesort

    • 如果排序和查找不是同一个字段,则会出现 using filesort

    • 避免方法:where 子句中出现哪些字段,order by 子句中就用哪些字段

      EXPLAIN
      SELECT *
      FROM
          instructor
      WHERE
          salary > 60000
      ORDER BY
          dept_name
      
  • 对于复合索引

    • 查询各子句中出现的字段最好不要跨列,保持和复合索引字段一样的顺序

    • 注意:whereorder by 按照复合索引的顺序使用,不要跨列或无序使用

      EXPLAIN
      SELECT *
      FROM
          student
      WHERE
          name = 'Zhang'
      ORDER BY
          dept_name
      

      student 表中的复合索引为(dept_name,name),但是该查询语句中,先出现 name 字段,后出现 dept_name 字段,和复合索引中字段的顺序不一致,导致复合索引失效,查询时没有使用该复合索引

using temporary:表示该 SQL 语句性能损耗大,用到了临时表

  • 一般出现在 group by 语句中
  • 避免方法:查询哪些列,就在 group by 子句中使用这些列

using index :该信息表示 SQL 语句性能提升,实现了索引覆盖

  • 表示不读取原文件,只从索引文件中获取数据,不需要回表查询

using where:该信息表示 SQL 语句性能损耗大,需要回表查询

假设 age 是索引列,但查询语句为:

SELECT
    age,
    name
FROM
    ...
WHERE
    age = ...

此语句中必须回原表查寻 name 字段的值,因此会显示 using where.

如执行以下命令:

EXPLAIN
SELECT *
FROM
    instructor
WHERE
    salary > 60000
GROUP BY
    dept_name

该查询中 dept_name 为索引字段,但是要显示所有字段,必须要回原表查询,因此会显示 using where

Chapter14 Transactions

14.1 Transaction Concept

  • 事务:是关系型数据库和非关系型数据库的一个显著区别
    • A transaction is a unit of program execution that accesses and possibly updates various data items.
    • 是用户定义的语句群,要么全部都执行,要么全部都不执行,不能执行一部分
    • 企业的实际应用:关系型数据库(重要的数据)+ 非关系型数据库(不太重要的数据)
  • 定义事务

显式定义

BEGIN TRANSACTION
SQL 1
SQL 2
COMMIT # 写到磁盘中

BEGIN TRANSACTION
ROLLBACK # 撤销之前的更新结果

隐式定义

当用户没有显式的定义事务的时候,DBMS 按缺省规则自动划分事务

  • ACID

    • 原子:一个事务要么执行要么不执行
    • 隔离:一个事务的执行不能被其他事务干扰
    • 持久:一旦一个事务被成功提交之后,它对数据库中的数据的改变就是永久性的
    • 一致:事务的执行结果必须使得数据库从一个一致性状态变到另一个一致性状态
    • 如何实现:并发控制恢复机制

14.2 并发控制/调度

  • 并发控制/调度:某一时刻,多个用户对同一个数据对象的访问
    • 并发调度不当产生的问题
      • 丢失修改:两个事务同时读了一个数据并且修改,先修改的修改丢失
      • 不可重复读:事务1读取数据后,事务2执行更新操作,事务1两次读同一个数据但是却得到不同的结果
      • 读脏数据:事务1在对数据做修改的时候,事务2读取了这个数据,但是事务1回滚了,事务2读的数据就是脏数据
    • 设计合适的并发调度策略

14.2.1 悲观法

基本方法 → \to 基于锁的机制:对要访问的数据对象上加锁

  • 排他锁:写锁,更新数据,能读能写

  • 共享锁:读锁,查询数据,能读

  • 关于锁上加锁:只能加多个共享锁,共享锁不能加排他锁。如果第一个锁是排他锁,其他的锁就不能继续往上添加

  • 问题:死锁现象——两阶段封锁协议

    • 如,T1:A, B, C

      在生长阶段(申请锁阶段):ABC 数据对象上的锁全部都要加上

      对ABC进行数据处理

      收缩阶段(释放锁阶段):ABC数据对象上的锁全部都释放

  • 可以对不同层次的数据对象加锁

    • 服务器级别的锁,让服务器变为只读(恢复)
    • 数据库级别的锁(数据库备份)
    • 数据表级别(并发控制)
    • 记录级别(细化的并发控制)
    • 字段级别(细化的并发控制)
  • 锁的使用:数据对象的级别,锁的类型,申请锁的时间,持有锁的时间(释放锁的时间)

    • 自己研究比较困难,容易造成死锁,不要亲自在开发的时候使用锁机制进行并发控制,使用事务的隔离级别来控制
  • 隔离级别:实际开发中使用的并发控制

    • Serializable:可串行化,所有事务顺序执行,代价最高,但是最可靠,保证所有的数据不一致情况都不会发生
    • Repeatable read:可重复读,并发度好,可以防止脏读,不可重复读,但会可能出现幻读,默认情况下锁定所有已经读取的行
    • Read committed :已提交读,一个事务不能读取其他数据未提交的数据,可以避免脏读,可能出现不可重复读,幻读
    • Read uncommitted:未提交读,允许其他事务读取一个事务正在读取的数据,以上问题都会出现

14.2.2 乐观的并发调度

查询数据是主要业务的应用场景
不使用锁机制,不强调先要占有某个数据对象,方法有

每个事务都可以对某个数据对象进行操作和更新

  • 时间戳
  • 版本控制

14.3 恢复机制——事务的持久性

  • 数据库的数据出现故障是不可避免的
  • 做备份(冗余数据)
  • 主数据文件做备份——基本数据——DBA——先写日志,再写数据库
  • 日志文件做备份——DBMS自动维护:记录对表的更新操作
    日志记录——写入日志文件
事务开始标记
	insert
	值
事务结束标记

一旦发生故障,DBMS检查日志文件,有一些日志记录是否完整:事务开始和结束标记
还有一些日志记录不完整:只有事务开始但是没有结束标记

MySQL单机备份
主从备份

Appendix A 编程语言访问数据库

A.1 基本访问流程

DBMS DBA → \to 直接操作 → \to DBMS (人数少)

开发人员:间接操作 → \to 编程语言 → \to DBMS(人数多)

java 访问 MySQL 的步骤:开发人员 → \to 框架工具 → \to SSM

  1. 找到合适的 API:加装驱动(类、属性、方法)
    • java:JDBC
    • ODBC:开放数据库互连
    • C#:ADO.NET
    • PHP

java:语言生态环境好,第三方工具包(已实现功能,类库、jar、war)

系统开发:广泛的利用第三方工具包

e.g. JDBC → \to jar → \to

  1. 连接到数据库,建立连接:conncetion
    • 连接类 → \to 编写连接字符串信息(数据库服务器IP、登陆账号密码、端口号、访问的数据库)
    • 使用 open() 方法打开,以建立连接
  2. 编写SQL字符串:CRUD
  3. 执行命令:命令类
    • command, statement, SQL命令
    • 属性,方法,CRUD,查询
  4. 接收 SQL 返回结果
    • 查询 → \to 结果集(10记录 → \to 遍历 → \to 页面显示)
    • 更新 → \to 返回一个整数(几行受到了影响)
  5. 关闭连接对象
  6. 定义一个事务
  7. try-catc

A.2 SQL注入攻击

因为 SQL 语句是多个字符串拼凑而成,通过一些特殊字符的编写,可以对传入的 SQL 语句进行修改,达到获取高级权限的目的

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class TestSQL_Injection {

    public static void main(String[] args) {
        Connection conn = null;
        try {
            // 1.加载驱动mysql8版本
            Class.forName("com.mysql.cj.jdbc.Driver");

            // 2.建立连接
            conn = DriverManager.getConnection("jdbc:mysql:///myschool? useSSL=false & serverTimezone=Hongkong", "root", "root");

            // 3.编写非法的SQL语句
		    /*SELECT * FROM users
			  WHERE id=666
			        AND username='xxx' OR '1'='1';*/

            String selectUser = "SELECT * FROM users "
                    + "WHERE id=666 "
                    + "AND username='xxx' OR '1'='1';";

            // 4.创建命令对象
            Statement stmt = conn.createStatement();

            // 5.执行并接收查询结果
            ResultSet rest = stmt.executeQuery(selectUser);
            // 循环读出数据
            while (rest.next()) {
                int id = rest.getInt("id");
                String username = rest.getString("username");
                System.out.println(id + " " + username);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                // 关闭连接
                assert conn != null;
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

A.3 参数化的SQL语句

将要执行的 SQL 语句参数化,填入字符串中,以达到防止 SQL 注入攻击的目的

注意:在 select 操作中,如果参数是 sql标识符或者列名,不可以使用 setString 参数化编写(SQL限制)

https://stackoverflow.com/questions/36192242/java-preparedstatement-sql-syntax-error

A.4 预编译的SQL语言

Appendix B 数据库恢复技术

单机

B.1 故障的种类

  1. 事务内部的故障(DBMS自动恢复 日志文件)

  2. 系统故障(DBMS自动恢复 日志文件)

  3. 介质故障(DBA恢复 备份数据+日志文件)

  4. 计算机病毒(DBA恢复 备份数据+日志文件)

B.1.1 事务内部的故障

事务内部更多的故障是非预期的,是不能由应用程序处理的

  • 运算溢出
  • 并发事务发生死锁而被选中撤销该事务
  • 违反了某些完整性限制而被终止等

事务故障仅指这类非预期的故障

  • 事务故障意味着

    • 事务没有达到预期的终点( COMMIT 或者显式的 ROLLBACK )
    • 数据库可能处于不正确状态。
  • 事务故障的恢复:事务撤消(UNDO

    • 强行回滚(ROLLBACK)该事务
    • 撤销该事务已经作出的任何对数据库的修改,使得该事务象根本没有启动一样

B.1.2 系统故障

  • 系统故障
    • 称为软故障,是指造成系统停止运转的任何事件,使得系统要重新启动。

B.1.3 介质故障

B.1.4 计算机病毒

B.2 恢复

  • 恢复操作的基本原理:冗余
    • 利用存储在系统别处的冗余数据来重建数据库中已被破坏或不正确的那部分数据
  • 恢复的实现技术:复杂
    • 一个大型数据库产品,恢复子系统的代码要占全部代码的10%以上

恢复机制涉及的关键问题

  1. 如何建立冗余数据
  • 数据转储/备份(backup):对主数据库文件进行备份
  • 登记日志文件(logging):.log
  1. 如何利用这些冗余数据实施数据库恢复

静态转储

  • 在系统中无运行事务时进行的转储操作
  • 转储开始时数据库处于一致性状态
  • 转储期间不允许对数据库的任何存取、修改活动
  • 得到的一定是一个数据一致性的副本
  • 优点:实现简单
  • 缺点:降低了数据库的可用性
    • 转储必须等待正运行的用户事务结束
    • 新的事务必须等转储结束

动态转储

  • 转储操作与用户事务并发进行

  • 转储期间允许对数据库进行存取或修改

  • 优点

    • 不用等待正在运行的用户事务结束
    • 不会影响新事务的运行
  • 缺点

    • 不能保证副本中的数据正确有效
    • 例:在转储期间的某时刻 T c T_c Tc,系统把数据 A = 100 A=100 A=100 转储到磁带上,而在下一时刻 T d T_d Td,某一事务将 A A A 改为 200 200 200。后备副本上的 A A A 过时了
  • 海量转储(全备份): 每次转储全部数据库(一般是第一次备份数据库时)

  • 增量转储: 只转储上次转储后更新过的数据 (后面的备份)

  • 海量转储与增量转储比较

    • 从恢复角度看,使用海量转储得到的后备副本进行恢复往往更方便
    • 如果数据库很大,事务处理又十分频繁,则增量转储方式更实用更有效
  • 登记日志文件

    • DBMS 自动完成
    • 只记录修改类操作
    • 以数据块为单位
  • 必须先写日志文件,后写数据库(因为写日志文件的操作比写数据库快的多)

    • 写日志文件操作:把表示这个修改的日志记录写到日志文件中
    • 写数据库操作:把对数据的修改写到数据库中

在恢复数据库的时候,可能有一段无法恢复,需要日志文件

image-20210617104406105

B.3 检查点技术

  • 具有检查点(checkpoint)的恢复技术
    • 在日志文件中增加检查点记录(checkpoint)
    • 增加重新开始文件
    • 恢复子系统在登录日志文件期间动态地维护日志

数据库集群

主从备份(主服务器处理用户请求)

多台从服务器:自动对主服务器的数据进行同步的更新——利用日志文件

### 回答1: 《数据库系统概念(第七版)》是一本经典的数据库教材,由Silberschatz、Korth和Sudarshan合著。该书详细介绍了数据库系统的基本概念、数据模型、关系代数、SQL语言、事务管理、并发控制、数据安全等方面的知识。该书内容深入浅出,适合初学者和专业人士阅读。 ### 回答2: 《数据库系统概念》(Database System Concepts)7th是一本介绍数据库系统原理和设计以及应用的经典教材。本书通过详细阐述数据库的基本概念,包括数据模型、数据库语言和系统体系结构等方面,帮助读者理解数据库的工作原理及其所能提供的功能。 本书的第一部分介绍了数据管理的基础概念,包括数据模型、数据规范化和ER模型等。读者可以了解到数据库的基本组成部分和如何抽象表达数据。第二部分是关于数据库语言的介绍,其中包括SQL语言、关系代数和数据工具等。读者可以了解到各种不同类型的查询和如何从数据库中获取所需的信息。第三部分则涉及数据库的实现和应用部署,其中包括存储管理、查询优化和事务等。 此外,本书还介绍了现代数据库中的最新技术,例如数据挖掘、XML数据管理和NoSQL数据库等。对于想要深入了解互联网时代数据库技术的读者十分有用。 总的来说, 《数据库系统概念》(Database System Concepts)7th是一本权威经典的数据库教材,适用于计算机科学、计算机工程和信息管理等专业的本科生和研究生学习使用。同时,对于研究院所和企业等需要使用数据库的专业人员也十分有帮助。 ### 回答3: 《数据库系统概念》第七版是一本经典的数据库系统教材,由Abraham Silberschatz、Henry F. Korth、S. Sudarshan合著。本书共分为13章,内容包括关系数据模型、SQL、存储结构和文件组织、索引和查询处理、查询优化、事务管理、并发控制、数据库恢复、分布式数据库、NoSQL等方面。本书的目的是帮助读者建立数据库管理系统的基础知识,以及如何设计和实现数据库系统。 本书的重要特点是:清晰明了、深入浅出、注重理论和实践结合,并且紧密跟踪数据库技术的发展和变化。在本书中,作者为读者提供了大量具有实际应用价值的实例、案例和代码,帮助读者理解和掌握各种概念和方法。 本书首先介绍了关系数据模型及其基本概念,如关系、属性、域、元组、主键、外键等,在此基础上介绍了SQL语言及其语法、查询分析、查询优化和数据库设计过程。此外,本书还介绍了存储结构和文件组织的基本原理、索引和查询处理的算法和数据结构、事务管理、并发控制、数据库恢复和分布式数据库等方面的知识。 本书还特别介绍了NoSQL数据库的基础知识和应用场景,如键/值存储、文档存储和列式存储等,为读者提供了一个了解和掌握这一新型数据库技术的机会。 总之,《数据库系统概念》第七版是一本非常优秀的数据库系统教材,尤其适合计算机科学和工程领域的学生和研究人员使用。无论是从理论还是实践方面来看,都是非常重要和有价值的参考书。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值