MySQL学习笔记(零)数据库原理
第一章:数据模型
这一章主要考选填、简答题。重点背以下东西
data\database\DBMS的定义、特点及其包含关系
数据的独立性,逻辑和物理
数据模型的组成三要素
三级模式和两级映射是什么,如何工作的——两层映像的作用就是让上层的模式感受不到下层的变化,从而实现独立性
数据控制:指的就是权限的授予和收回,
为什么要解决数据冗余?
数据冗余(Data Redundancy) 之所以被认为是产生数据不一致的根本原因,是因为它创造了同一信息多个独立副本并存的环境,却没有建立同步更新的机制,导致在更新时无法保证所有副本同时改变,从而引发矛盾
文件系统就具有数据冗余的缺点,无法保证当某一个副本更新的时候,其他与之关联的副本也随之更新,从而不能保证数据库的一致性。
第二章:关系代数
基本的五个关系运算
根据题目要求写查询的关系代数式——重点是多选、难点的
为什么并、差、选择、投影、笛卡尔积是五个基本运算?
因为它们构成了一个完备集:这五个运算相互独立,且其他的关系代数运算(如交、连接、除等)都可以用这五个运算组合推导出来。
以下是常见的派生运算及其推导公式:
1. 交运算
2. 连接运算
- 先做 笛卡尔积 ( ):把所有可能的组合都列出来。
- 再做 选择 ( ):只保留那些满足连接条件 ( ) 的组合。
- 自然连接可以在此基础上加上投影去掉重复的同名列。
3. 除运算
(假设 A 是 R 独有的属性集,B 是 S 的属性集,且
- :找出 R 中所有可能的候选值(如所有学生)。
- :
- 先做笛卡尔积 ( ):让每个候选值与 S 中所有值配对(想象每个学生配上所有课程)。
- 减去 ( R ):去掉实际存在的配对,剩下的就是“缺失的配对”(如张三缺了数学课没选)。
- 投影 ( ):找出有缺失配对的候选者(有过缺课记录的学生)。
- ( T1 - T2 ):从所有候选者中减去那些有缺失的人,剩下的就是拥有全部 S 的人。
实战讲解
传统的集合运算并不要求所有的属性名字一样,只需要取值范围相同(域)即可。
已知关系模式S(sno,sname,age,sex),SC(sno,cno,Grade),C(cno,cname,teacher)
查询至少选修1号课程和3号课程的学生号码
这种选修多个的一般用除法(除法的作用就是找出符合多个条件的元组),得到符合多个条件的元组
而除法会消除相同的属性,这里就用课程号。
由题,得到 这样得到选择了1、3其中一个的元组,然后只投影cno即可
然后,用 除去投影的就可以得到结果了
最终就是
查询张三没有选修过的课程的课程号
首先,关系代数中不存在!=,没有不符合的说法
那么,解决思路就是正难则反,先找出张三选修过的课程,让所有的课程-张三选的=张三没有选的
所以,思路就清晰了。
但是SQL语句中没有专门的减法,怎么实现呢?
常见的思路是转换逻辑,也就是说,张三没有选修的课程=不存在课程张三选修了
解答如下
1 | select cno from C |
查询选修了全部课程的学生学号和姓名
关系代数: 的作用是实现至少有的功能,比如RS,其中S有AB,R只要是S的父集就行
用关系代数很好实现,用除法找到符合条件的,然后连接就行
但是SQL语句没有专门的除法,我们应该如何实现呢?
以下是两种思路
- 方法1:如果一个学生选的课的数量,等于课程表中总的课程数量,那么他就选了全部课程
- 方法2:利用逻辑代数,选修了全部课程=没有一门课他没有选修
方法1
1 | SELECT S.sno, S.sname |
方法2需要多层嵌套,不建议使用。
1 | SELECT S.sno, S.sname |
EXISTS 只关心子查询是否返回行,不关心返回的具体内容。优化器在执行时,会把 SELECT * 自动优化成 SELECT 1 或 SELECT 'any',根本不会去实际获取数据
具体讲解
S(学生表)
| sno | sname | age | sex |
|---|---|---|---|
| 1 | 张三 | 20 | M |
| 2 | 李四 | 21 | F |
| 3 | 王五 | 20 | M |
C(课程表)
| cno | cname | teacher |
|---|---|---|
| A | 数学 | 赵老师 |
| B | 英语 | 钱老师 |
SC(选课表)
| sno | cno | grade |
|---|---|---|
| 1 | A | 85 |
| 1 | B | 90 |
| 2 | A | 78 |
| 3 | B | 88 |
总课程数 = 2(A、B)
找出选了全部课程的学生学号和姓名。
预期结果:只有 张三(sno=1) 选了 A 和 B。
1 | SELECT 1 |
这个子查询的作用:检查某学生(S.sno)是否选了某门课(C.cno)。
举例:当外层 S.sno = 1,C.cno = ‘A’
代入:
1 | SELECT 1 |
从 SC 表中找:
| sno | cno | grade |
|---|---|---|
| 1 | A | 85 |
| 1 | B | 90 |
→ 找到一行(sno=1, cno=A)
→ 子查询返回 1 行(内容是 1)
→ 存在(EXISTS 为 TRUE)
举例:当外层 S.sno = 1,C.cno = ‘B’
找 SC 表:
| sno | cno | grade |
|---|---|---|
| 1 | A | 85 |
| 1 | B | 90 |
→ 找到一行(sno=1, cno=B)
→ 存在
举例:当外层 S.sno = 2,C.cno = ‘B’
找 SC 表:
| sno | cno | grade |
|---|---|---|
| 2 | A | 78 |
→ 没有 sno=2 且 cno=B 的行
→ 不存在(EXISTS 为 FALSE)
1 | SELECT * |
这一层的逻辑:
对于某学生 S.sno,遍历所有课程 C.cno,看是否存在一门课,这个学生没有选。
对学生 1(sno=1)执行这一层
循环 C 表:
- 课程 A:最内层查询(sno=1, cno=A)→ 存在(TRUE)
NOT EXISTS (TRUE)→ FALSE → 不保留 A - 课程 B:最内层查询(sno=1, cno=B)→ 存在(TRUE)
NOT EXISTS (TRUE)→ FALSE → 不保留 B
结果:没有课程被保留
→ 这一层子查询返回 空集(0 行)
对学生 2(sno=2)执行这一层
循环 C 表:
- 课程 A:最内层查询(sno=2, cno=A)→ 存在(TRUE)
NOT EXISTS (TRUE)→ FALSE → 不保留 A - 课程 B:最内层查询(sno=2, cno=B)→ 不存在(FALSE)
NOT EXISTS (FALSE)→ TRUE → 保留 B
结果:保留课程 B
→ 这一层子查询返回 1 行(B 这一行)
对学生 3(sno=3)执行这一层
循环 C 表:
- 课程 A:最内层查询(sno=3, cno=A)→ 不存在(FALSE)
NOT EXISTS (FALSE)→ TRUE → 保留 A - 课程 B:最内层查询(sno=3, cno=B)→ 存在(TRUE)
NOT EXISTS (TRUE)→ FALSE → 不保留 B
结果:保留课程 A
→ 这一层子查询返回 1 行(A 这一行)
1 | SELECT S.sno, S.sname |
这一层的逻辑:
筛选出那些“中间层子查询返回空集”的学生。
对学生 1(sno=1)
中间层子查询结果:空集(0 行)
NOT EXISTS (空集) → TRUE(因为不存在任何他没选的课)
→ 保留学生 1
对学生 2(sno=2)
中间层子查询结果:1 行(课程 B)
NOT EXISTS (有 1 行) → FALSE
→ 不保留学生 2
对学生 3(sno=3)
中间层子查询结果:1 行(课程 A)
NOT EXISTS (有 1 行) → FALSE
→ 不保留学生 3
结果
| sno | sname |
|---|---|
| 1 | 张三 |
✅ 正确!只有张三选修了全部课程。
注意看的时候要从内向外看,先看最内层,再结合看最内层和倒数第二层,依次类推。
第三章:SQL语句
DDL、DML、DCL、DQL的区别和典型语句
1. DDL(数据定义语言)
- 定义: 用于定义、修改或删除数据库中的对象结构(如数据库、表、视图、索引等)。也就是说处理对象是表,索引这种的就是DDL。
- 典型语句: 比如
create tabledrop index - 特殊:audit语句是DDL
2. DML(数据操作语言)
- 定义: 用于操作数据库中存储的实际数据。
- 典型语句: 插入删除和更改
insert delete update处理的对象是元组,实际的数据
3. DCL(数据控制语言)
- 定义: 用于控制数据库的访问权限、用户权限和事务。涉及到授权的就是DCL
- 典型语句:
CREATE USER/DROP USER:创建/删除用户grant revoke授权和回收权限等
4. DQL(数据查询语言)
- 定义: 专门用于从数据库中查询数据。但在严格分类中单独列为DQL,因为它只负责查询,不修改数据。
- 典型语句:
select语句
通用分析方法
就是要用分析英语长难句的方法分析实际需求,然后转为正确的sql语句
三段论,如果有从句也同样按照此方法分析
比如:查询所有年龄在20岁以下的学生姓名及其年龄
- 首先分析查的是什么——姓名、年龄
- 然后从哪里查——学生表
- 查询条件是什么——age<20
最后基本上是补充限制条件(比如distinct防止重复、取别名等)、从后往前写,然后按照格式调整顺序即可
这里就是where age < 20 from Student select name,age
组合为
1 | select name, age from Student where age < 20; |
如果涉及到分组,select后面只能跟被分组的属性或者是聚合函数,并且只能使用having作为限制条件而不能使用where。
查询
1 | select <属性名> |
表明你要查的是什么,这里的属性名可以是表达式,也可以是表中没有的(比如字符串等)
1 | from <表名或者视图名> |
从哪一个表(视图)中查
1 | where <条件> |
查询记录所需要符合的条件
1 | group by <列名> |
查完之后按照哪一列分组,然后再展示
1 | order by <列名> |
最后给记录排序的时候按照哪一列排序,升序还是降序(默认升序)
查询的背后
1 | select name,age |
在查询的背后,首先用student.sno = sc.sno 将两个表合成一张大表,然后在此表的基础上选择符合条件的元组。
常考的SQL语句
剩下的见书,常考的还有创建表、字符串的模糊匹配、嵌套查询、更新、插入、定义视图,见到一个查一个
实战讲解
注意只有分组了之后才能使用having,where语句中不能出现聚集函数
HAVING 的语法规则:只能使用「分组字段」或「聚合函数(count ()/sum ()/avg () 等)」作为判断条件
WHERE 分组前过滤行,HAVING 分组后过滤组
还有一点就是and前后语句的顺序问题
虽然可以调换顺序,但建议按照逻辑清晰的方式排列条件,比如先写连接条件,后写过滤条件,这样可以提高代码的可读性。
复杂的查询语句
执行顺序(死记):from → where → group by → having→ select
比如:统计各科不及格超过3的学生的人数——逻辑理解(通俗):先把「不及格的成绩挑出来」,再「按学号分组」,最后「数每个组有多少个不及格的科目」,超过3的才选择,没有超过3的不展示。
1 | select sno, count(*) |
空值的使用提醒
SQL 中判断字段是否为 NULL,唯一正确写法:字段 IS NULL / 字段 IS NOT NULL;
NULL 是「未知值」,不能用 =/!=/</> 等普通运算符匹配,这是 SQL 的语法铁律,用字段 + 运算符 + 比较值查不到任何值。
第四章:数据库安全性
主要出选填、简答题
背安全级别划分,还有以下的SQL语句
授权和回收权利
- 授予什么权利
- 针对什么对象
- 给谁
ex:在视图上授予王平查询学生表成绩的权利
1 | grant select(grade) # 权利 |
有时候题目还要求使用WITH GRANT OPTION或者是级联等,注意
审计
- 对什么操作审计
- 针对哪一个表
ex:对修改sc表的结构及其数据的操作进行审计
1 | audit alter,update # 操作 |
第五章:数据库完整性
[!NOTE]
注意为了和实际应用相契合,这里统一用键指代码。
三个完整性定义要背,同时题目喜欢考在创建表的时候限制主键和外键、属性的范围和要求等,SQL也要会写
实体完整性
就是主键的问题,唯一非空
参照完整性——外键
简单来说,就是参照的一旦改动与被参照的不一致,就拒绝,被参照的改变要根据策略做出回应,是拒绝还是级联更新还是置空。
用户定义完整性
就是数据要符合要求,比如年龄不能有小数,性别只有两个等。
用sql语句规定其完整性,比如NOT NULL 不能为空,Sex CHAR(2) CHECK(Sex IN('男','女')) 性别只有两个
常见的有NOT NULL UNIQUE CHECK
当然用的最多的就是CONSTRAINT语句
总结:三大完整性区别
实体:既然实际存在,那么就不为空
参照:外键为空或一致
定义:自行规定的取值范围。
断言和触发器
断言类似各个计算机语言的assert,
而触发器相当于JavaScript的事件监听和触发
第六章:关系数据库理论
要解决的问题就是insert、update和delete的异常以及冗余的数据,通过合理规划依赖(也就是如何更好的设计表),实现更好的数据库维护
这个思想其实与函数的单一性功能非常相似,也就是一张表“只干一件事”,把复杂的表拆分成几个简单的表,这样有助于更好维护数据库。
范式(Normal Form-NF)
定义:符合某种级别的关系模式的集合,人话就是
1NF:不可分
2NF:非主完全依赖于任意候选码(如果能推出多个,那么每一个都要满足)
3NF:非主不存在对候选键的传递依赖。也就是消除非主属性的传递依赖,解决方法一般是:拆表
对于比较复杂的关系、依赖和隐蔽的传递依赖,需要通过定义判断
即R 满足 3NF,如果对 F 中每个函数依赖 X→Y(其中 Y 不在 X 中):X 是超键或者Y 的每个属性都是主属性(属于某个候选键)。
然后对于隐藏的传递依赖,把所有候选键写出来,然后看能不能传递推导推出非主属性,都不能则说明是3NF
BCNF:X推出Y,Y不属于X()且X必须是键(书本上说的是除了X之外没有决定性因素,X不能是键的一部分)。换句话说就是要消除主键之间的依赖。
此时BCNF基本消除了insert和delete异常,但是没有解决冗余问题
4NF:每一个非平凡多值依赖X–>Y,其中X都是键,解决了冗余问题。
多值依赖
用例子来解释:【例】关系Teaching(C,T,B)中,对于C的每一个值,T有一组值与之对应,而不论B取何值。因此T多值依赖于C,即C→→T。
表示为(C,B)->T,但是T与B没有关系。注意这里推出的是一组值而不是一个
如果画出图来,那么T与B的关系很像"全相联映射"。
判断的方法
比如关系模式STJ(S,T,J),分别表示学生、老师和课程,一个老师只教一门课,每门课有若干老师,某一个学生选定某门课,就对应一个固定的老师。
首先,先写出所有的依赖,这里是
然后一个个确定键,看相应的依赖,从第二范式开始判断是否符合
这里键分别是(S,T),(S,J),注意T不是键。这里所有的属性都在候选键中,所以没有非主属性,因此满足2NF要求
同样没有码传递依赖,所以满足3NF
这里T决定J,J不包含于T,但是T不是码,所以不满足BCNF
综上,关系模式满足3NF
2NF的判断问题
比如(Sno,Gno)->Dno,(Sno,Dno)->Person,候选键是(Sno,Gno),这个时候要多推导一下,由候选键推出Dno,Dno再结合主属性推出Person,对于Person来说是传递依赖,而不是部分函数依赖,因为(Sno,Dno)并不是候选键的真子集,不能称之为部分函数依赖,所以满足的是2NF,而不满足3NF。
如何化为BCNF?
以上题为例,有一个T->J,可以通过分解,把这个导致它不是bc范式的这个函数依赖给它分解出来。比如这里分成ST(S,T)和(T,J) 这样两个关系模式分别满足BCNF了。
难点:公理系统
闭包:比如 意思就是求在已知AB属性的情况下能够推出哪些属性。
这里不要求掌握推理过程和定义,直接放弃,以后有需要再学吧
⭐⭐⭐模式分解
涉及到分库分表,我用一个实际例子来讲解如何分解表,以后工作分表、设计表的时候会很有帮助。
已知学生关系模式S(Sno,Sname,Sdept,Sdname,Course,Grade) 其中Sno为学号,Sname为学生名字,Sdept为系名,Sdname为系主任名字,Course为课程名,Grade为成绩
- 写出关系模式S的基本函数依赖和主键
- 原关系S为第几范式?为什么?请说明如何分解为高一级的范式
- 请在(2)的基础上分解为高一级的范式,并说明为什么?
1)首先看当某一个属性(或者一组)确定的时候,另一个属性是否唯一确定
比如当学号确定的时候,学生名字就唯一确定,则有
同理:当学号和课程同时确定时,才确定成绩,则有
而当Sname确定的时候,无法确定Sdname,因为学生有可能重名,
依次类推分析…
得到基本函数依赖为
主键就是当某一个或者一组属性确定的时候,可以唯一确定一条记录(元组)
这里主键就是(Sno,Course),而且缺一不可。
2)从1NF开始分析
属性不可再分吗?是,那么就满足第一范式(1NF)
非主属性完全依赖于任意候选码?这里非主属性就是不属于候选码的属性,候选码是键,可以唯一确定一条记录。
这里候选码就是主键(Sno,Course),其他的属性就是非主属性,而根据1) Sname只需要Sno就可以确定,不需要Course,所以为否。
因此,这个模式为1NF
那么如何分解呢?
出问题的地方就是Course作为了主键的一部分,而Sname、Sdept都是不依赖于Course的,所以解决问题的方法就是让Course远离Sname和Sdept。
因此我们可以分解为
S1(Sno,Sname,Sdept,Sdname) S2(Sno,Course,Grade)
这样在每一个关系模式中,非主属性完全依赖于任意候选码,因此两个都是2NF
3)分析2)S1得到这样的基本函数依赖
非主属性存在对主键的依赖传递吗?发现Sno可以通过Sdept决定Sdname,因此存在函数依赖,所以不是3NF。
那么如何分解呢?
出问题的地方就是Sdept充当了桥梁,那么过河拆桥即可,将Sdept分别给Sno和Sdname
因此我们可以分解为
S1(Sno,Sname,Sdept) S3(Sdept,Sdname)
这样在每一个关系模式中,非主属性不存在对主键的依赖传递,因此两个都是3NF
第七章:数据库设计
这部分实践要重于理论,也就是说,理论过一下就行,最终在做项目的过程中体会到设计的全过程就行。
计算机很多知识都是这样,先有工程实践,然后将工程实践抽象为知识。
概念结构设计
这个是重点部分。
目前常见的设计方法是:画E-R图、画UML图等,理论上喜欢用E-R,而实际应用偏UML
一切以实际开发为准,这里因为复试需要就学习E-R模型
当E-R图画好之后,就是看图说话,把基本的依赖都写出来,这样再根据不同的范式要求设计表就是逻辑结构设计。
如何画E-R图呢?我画的E-R图见UML图
首先,当只要求画局部的E-R图时,可以适当省略无关信息(做题的要求)
比如学生有学号、姓名、性别、课程,一开始先将其作为属性,然后读题,如果课程还可以细分,那么就将课程作为实体并联系,同时把本来学生的课程名属性等归到课程的实体属性中,以免重复。同时也要标记对应关系,这涉及到下一步的转换。
逻辑结构设计——如何将画完的E-R图转化为关系模式
首先,将所有实体都看作一个表,写其所有的属性。
然后(以下是一般情况)
首先分析1:1的关系:可以直接将关系的两个实体的键+关系的属性单独合成一张表,然后这两个实体自己各自作为一张表,或者是把联系的另一端(B)的键+属性并入到另一端(A)(这叫合并),那么A中有自己的属性+B的键+关系的属性,B中就只有自己的属性
再分析1:n的关系:将1端的实体的键和n端的实体所有属性+关系的属性合成一张表放入n端中,1保持不变
再分析m:n的关系:把两端的键+联系的属性拿出来单独合成一张表,两端也作为独立的一张表
最后,如果有传递性的也要同理处理
第八章:嵌入式SQL
目前只考了存储过程
存储过程和函数
示例:创建一个过程,将学号为s1,课程为c1的成绩修改为g1
1 | CREATE OR REPLACE PROCEDURE PROC3 |
第九章:关系查询处理和优化
P书285页,这里是重点,以后无论是设计还是查询都要学会其中的方法,这也是区分一般程序员和优秀程序员的关键知识。
背查询处理的四个步骤,了解查询优化算法、代数优化的方法
语法树的查询优化过程
- 首先拿到关系代数式子写成语法树形式
- 可以下移的选择往下移到底
- 把不需要的列投影去掉
- 分组:一个笛卡尔积(二元运算)分为一组
第十章:数据库恢复技术
掌握事务的四特点、四种故障、检查点。
第十一章:并发控制
注意区分幻读和脏读——关键是脏读涉及到事务的撤销
S锁和X锁的相容关系、两段锁协议
目前还没有看到难的
新技术篇
等研究生的时候再学
参考资料
- 数据库系统概论/王珊,萨师煊编著.–5版.–北京:高等教育出版社,2014.9(2022.5重印) ISBN 978-7-04-040664-1
- deepseek :用于生成database实践案例





