数据库
数据库
基础知识
三级模式-两级映像

概念模式也称模式,是数据库中全部数据的逻辑结构和特征的描述,它由若干个概念记录类型组成,只涉及“型”的描述,不涉及具体的值。(表级)
- 与数据的物理存储细节和硬件环境无关 。 逻辑层通过相对简单的结构描述了整个数据库。尽管逻辑层简单结构的实现涉及了复杂的物理层结构,但逻辑层的用户不必知道这些复杂性
- 与具体的应用程序、开发工具及高级程序设计语言无关
- 模式的定义:
- 数据的逻辑结构(数据项的名字、类型、取值范围等)
- 描述记录间的联系、操作、数据的完整性和安全性等要求
外模式也称用户模式或子模式,是用户与数据库系统的接口,是用户需要使用的部分数据的描述。它由若干个外部记录类型组成。用户使用数据操纵语言对数据库进行操作,实际上是对外模式的外部记录进行操作。 (视图级)
内模式也称存储模式,是数据物理结构和存储方式的描述,是数据在数据库内部的表示方式。 定义所有的内部记录类型、索引和文件的组织方式,以及数据控制方面的细节。(文件级)
- 数据在数据库内部的表示方式: 记录的存储方式(顺序存储,按照B树结构存储,按hash方法存储)、索引的组织方式、数据是否压缩存储、数据是否加密、数据存储记录结构的规定
在一个数据库系统中,『模式』与『内模式』都只能有一个,但『外模式』可以有很多个
逻辑独立性:数据的逻辑结构发生变化后,用户程序也可以不修改。但是为了保证应用程序能够正确执行,需要修改外模式和概念模式之间的映像。
物理独立性:当数据的物理结构发生改变时,应用程序不用改变。但是为了保证应用程序能够正确执行,需要修改概念模式和内模式之间的映像。
SQL 语句
表A记录如下:
aID | aNum |
---|---|
1 | a20050111 |
2 | a20050112 |
3 | a20050113 |
4 | a20050114 |
5 | a20050115 |
表B记录如下:
bID | bName |
---|---|
1 | 2006032401 |
2 | 2006032402 |
3 | 2006032403 |
4 | 2006032404 |
8 | 2006032408 |
left join
1 |
|
aID | aNum | bID | bName |
---|---|---|---|
1 | a20050111 | 1 | 2006032401 |
2 | a20050112 | 2 | 2006032402 |
3 | a20050113 | 3 | 2006032403 |
4 | a20050114 | 4 | 2006032404 |
5 | a20050115 | NULL | NULL |
right join
1 |
|
aID | aNum | bID | bName |
---|---|---|---|
1 | a20050111 | 1 | 2006032401 |
2 | a20050112 | 2 | 2006032402 |
3 | a20050113 | 3 | 2006032403 |
4 | a20050114 | 4 | 2006032404 |
NULL | NULL | 8 | 2006032408 |
inner join
1 |
|
aID | aNum | bID | bName |
---|---|---|---|
1 | a20050111 | 1 | 2006032401 |
2 | a20050112 | 2 | 2006032402 |
3 | a20050113 | 3 | 2006032403 |
4 | a20050114 | 4 | 2006032404 |
关系代数
投影:投影运算 Projection 是从垂直方向进行运算, 即在关系R中选择出若干属性列组成新的关系 ,记作:$\pi$
选择运算 Selection 从关系R中选择满足给定条件的行 ,记作 : $\sigma$
笛卡尔积 Cross product
sql语句:
1 |
|
自然连接
sql语句:
1 |
|
数据库控制
数据安全控制
存取控制
对用户进行授权,包括操作类型(如查找、插入、删除、修改等动作)和数据对象(主要是数据范围)的权限。 Grant(授权) Revoke (取消授权)
1 |
|
并发控制
ACID
事务的ACID特性
原子性(Atomicity) 是指事务包含的所有操作要么全部成功,要么全部失败回滚。这些操作是一个整体,不能部分地完成。
一致性(Consistency)是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。
隔离性(Isolation)是指一个事务的执行不能被其他事务干扰,即一个事务内部的操作及使用的数据对并发的其他事务是隔离的。
持久性(Durability,永久性)是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,无论发送何种故障,都不应对其有任何影响。
读写锁
处理并发控制的主要方法是采用封锁技术。它有两种类型:排他型封锁(X 封锁)和共享型封锁(S 封锁),分别介绍如下
排他型封锁(简称 X 封锁 、 写锁) : 加了 X 锁以后,任何的锁都不能加
共享型封锁(简称 S 封锁 、 读锁): 加了 S 锁以后,可以继续加 S 锁 , 不能加 X 锁
并发带来的问题
丢失更新 ( 两个事务都在写 ,后面写的覆盖了前面写的 )
读脏数据 (A还没写完B就来读,A突然间回滚 )
1、在事务A执行过程中,事务A对数据资源进行了修改,事务B读取了事务A修改后的数据。
2、由于某些原因, 事务A 并没有完成提交,发生了RollBack操作,则事务B读取的数据就是 脏数据 。
这种读取到另一个事务未提交的数据的现象就是脏读(Dirty Read)。
不可重复读 ( A 读了两次 , B在这期间跑过来写数据 )
事务A读取了两次数据资源,在这两次读取的过程中事务B修改了数据,导致事务A在这两次读取出来的数据不一致。
幻读
事务B前后两次读取同一个范围的数据,在事务B两次读取的过程中事务A新增了数据,导致事务B后一次读取到前一次查询没有看到的行。
幻读和不可重复读有些类似,但是幻读强调的是集合的增减,而不是单条数据的更新。

事务级别
读未提交(Read Uncommitted) : 所有的事务都可以看到其他未提交的事务的执行结果。
读已提交(Read Committed) : 一个事务只能看见已经提交事务所执行结果。 可以防止脏读问题,但会出现不可重复读及幻读问题
可重复读(Repeatable Read):一个事务多次读同一个数据,在这个事务还没结束时,其他事务不能访问该数据(包括了读写)
串行化 : 它要求事务序列化执行,事务只能一个接着一个地执行,不能并发执行
封锁协议
一级封锁协议。事务T在修改数据R之前必须先对其加X锁,直到事务结束才释放X锁。可防止丢失修改

二级封锁协议。一级封锁协议加上事务T在读取数据R之前先对其加S锁,读完后即可释放S锁。可防止丢失修改,还可防止读“脏”数据

三级封锁协议。一级封锁协议加上事务T在读取数据R之前先对其加S锁,直到事务结束才释放S锁。可防止丢失修改、防止读“脏”数据与防止数据(不可)重复读

两段锁协议。可串行化的。可能发生死锁
故障恢复
故障关系 | 故障原因 | 解决方法 |
---|---|---|
事务本身的可预 期故障 | 本身逻辑 | 在程序中预先设置Rollback语句 |
事务本身的不可 预期故障 | 算术溢出、违反 存储保护 | 由DBMS的恢复子系统通过日志, 撤销事务对数据库的修改,回退到 事务初始状态 |
系统故障 | 系统停止运转 | 通常使用检查点法(系统重启时自 动完成) |
介质故障 | 外存被破坏 | 一般使用日志重做业务 |
重做日志(Redo Log) 、 撤销日志(Undo Log)
属性 | redo log | undo log |
---|---|---|
作用 | 记录数据库事务的更改,用于在 MySQL 服务器崩溃后恢复数据 | 记录数据库事务的回滚信息,用于在用户撤销或回滚事务时恢复数据 |
记录的内容 | 数据库事务的更改 | 数据库事务的旧数据 |
使用场景 | 用于数据库恢复 | 用于数据库撤销和回滚 |
数据库设计过程

- 需求分析:即分析数据存储的要求,产出物有数据流图、数据字典、需求说明书。获得用户对系统的三个要求:信息要求、处理要
求、系统要求。
概念结构设计: 将依据需求分析的结果转换成一个独立于具体DBMS的概念模型,即实体关系图
- 工作步骤包括:选择局部应用、逐一设计分E-R图和E-R 图合并。
逻辑结构设计: 将概念结构转换为某个DBMS所支持的数据模型,并对其进行优化,包括对关系模型的规范化
- 将E-R图,转换成关系模式。主要工作步骤包括确定数据模型、将E-R 图转换成为指定
的数据模型、确定完整性约束和确定用户视图
物理设计: 逻辑模型在计算机中的具体实现方案
- 步骤包括确定数据分布、存储结构和访问方式。
数据库实施阶段。根据逻辑设计和物理设计阶段的结果建立数据库,编制与调试应用程序,组织数据入库,并进行试运行。
数据库运行和维护阶段。数据库应用系统经过试运行即可投入运行,但该阶段需要不断地对系统进行评价、调整与修改。
概念结构设计

E-R模型
实体是 E-R 模型的基本对象,是对现实世界中各种事物的抽象
属性是不可分割的数据单位,用于描述实体所具有的特征,例如教师实体具有姓名、性别、地址等属性。
在 E-R 模型中,实体一般是长方形来体现,而属性则是椭圆形,如果属性是主码(主键),则在属性名称下用画下划线来表示

复合属性 :某些属性还可以划分具有独立意义的子属性。例如人的姓名可划分为“姓”和“名”;

属性按照取值的个数还可以分为 单值属性 和 多值属性
单值属性 是指此属性对于同一个实体只能取一个值,如人的姓名、性别
多值属性 属性可能取多个值
多值属性的描述与单值属性不一致,它采用双线椭圆表示,并且在实际开发过程中,如果有多值属性出现,一般要将其另归为实体或联系。

可选属性,即并不是所有的属性都必须有值,有些属性的可以没有值,这就是可选属性,在椭圆的文字后用“(O)”来表示。
实体间的联系
联系的种类 : 1:1 1:n n:m
联系的存在性 :

它表示一个项目至少要有一个员工参加(强制性的),而一个员工可能不参加任何一个项目(可选的)。
高级 E-R 构造
**超类 ** : 将几个实体中的某些公共属性概括出来,提取出一个更高层次的实体
泛化 : 将几个实体中的某些公共属性概括出来,提升为一个高一层次的超类

汇集层次
汇集(Aggregation)是另一种重要的信息抽象手段,描述了整体和部分之间的联系
汇集层次中没有继承,所以也不以超类、子类来称呼相关的实体,而是称为父实体和成份实体。
汇集的概念类似于面向对象概念中的聚合关系

弱实体
不能独立存在,必须要依赖于一个强实体 。在 E-R 图中用双线框表示弱实体。

设计步骤
局部 E-R 模型设计
一般情况下我们会先按照需求模块进行局部 E-R 模型的构建
建立 E-R 模型的步骤:区分实体和属性 → 找出汇集层次 → 找出泛化层次 → 找出弱实体 → 定义联系。
E-R 模型的集成
合并:消除局部 E-R 图之间的不一致,生成初步 E-R 图;
优化:消除(或减少)数据冗余,生成全局 E-R 图。
集成的方法:
多个局部E-R图一次集成。
逐步集成,用累加的方式一次集成两个局部E-R。
集成产生的冲突及解决办法:
- 属性冲突
- 属性域冲突,即属性值的类型、取值范围不一致。例如,员工的工号是使用数值型还是字符型。
- 属性取值冲突。例如,学生的成绩有的以百分制计,有的以五分制计。
- 命名冲突。
- 同名异义:不同意义的对象在不同的局部应用中具有相同的名字。例如,“单位”既可以表示人员所在部门,也可以作为长度、重量等度量的属性。
- 异名同义:同一意义的对象在不同的局部应用中具有不同的名字。例如学校的“系别”与“学院”实际上是同一实体。
- 结构冲突。
- 同一对象在不同局部应用中具有不同的身份。例如局部模型A中的某实体在另一局部模型 B 中被设计为属性,这就造成了结构上的冲突。
- 同一对象在不同局部应用中的属性组成不完全相同。例如,对同一类“员工”这一对象,在局部模型 A 中其属性为工号、姓名、性别、年龄4个属性,而在另一局部模型 B 中的属性为工号、姓名、所在部门 3 个属性组成。
- 相同实体之间的联系在不同局部模型中不一致。例如,在局部应用 A 中实体 E1 和 E2 是一对多联系,而在局部应用 B 中却是多对多联系。
逻辑结构设计

- 确定数据模型、将E-R 图转换成为指定的数据模型、确定完整性约束、确定用户视图
将 E-R 图转化为关系数据模型
数据模型三要素:数据结构、数据操作、数据的约束条件。

完整性约束:
- 实体完整性约束:规定基本关系的主属性不能取空值。
- 参照完整性约束:关系与关系间的引用,其他关系(外键)的主键或空值。
- 用户自定义完整性约束:应用环境决定。 ( 例如:年龄的取值范围 )
规范化理论
键
超键:能唯一标识此表的属性的组合。
候选键:超键中去掉冗余的属性,剩余的属性就是候选键。
主键:任选一个候选键,即可作为主键。
外键:其他表中的主键。
主属性:候选键内的属性为主属性,其他属性为非主属性

公理系统
函数依赖的公理系统(Armstrong)设关系模式R<U , F> , U是关系模式R的属性全集,F是关系模式R的一个函数依赖集。对于R<U,F>来说有以下的:
自反律:若Y⊆X⊆U,则X→Y为F所逻辑蕴含 ( 整体可以推导出局部)
增广律:若X→Y为F所逻辑蕴含,且Z⊆U,则XZ→YZ为F所逻辑蕴含
传递律:若X→Y和Y→Z为F所逻辑蕴含,则X→Z为F所逻辑蕴含
合并规则:若X→Y,X→Z,则X→YZ为F所蕴涵
伪传递率:若X→Y,WY→Z,则XW→Z为F所蕴涵
分解规则:若X→Y, Z⊆Y , 则X→Z为F所蕴涵 (自反 + 传递) 。 可以推导出整体,就可以推导出整体的一部分
平凡函数依赖 、非平凡函数依赖
X→Y,但 Y ⊈ X则称X→Y是**非平凡的函数依赖 **。
- (Sno,Cno,Grade) (Sno,Cno)→ Grade
X→Y,但Y ⊆ X则称 X→Y是平凡的函数依赖。 ( 父集可以推导出子集 , 是一句废话)
- Grade(Sno,Cno)→ Sno
- Grade(Sno,Cno)→ Cno
范式
第一范式1NF:若关系模式R 的每一个分量都是不可再分的数据项,则关系模式R 属于第一范
式。记为R∈1NF。
第二范式:如果关系R属于1NF,且每一个非主属性完全函数依赖于任何一个候选码

第三范式:在满足1NF的基础上,表中不存在非主属性对码的传递依赖。
BCNF : 3N F消除了主属性对码的部分函数依赖和传递函数依赖

没有达到(3NF)的数据库,可能存在的问题包括:数据冗余、更新异常(修改操作一致性问题)、插入异常、删除异常。

保持函数依赖、无损分解
保持函数依赖

R1( A , B) A → B R2( B , C) B → C 保持函数依赖

A → C 是多余的,可以有其他函数依赖推导。
R1( A , B) A → B
B → C 无法被还原
没有保持函数依赖
无损分解

1、存在同名属性列 “学号” , 以及 学生(学号,姓名)表中,保留了 学号→姓名 函数依赖

2、存在同名属性列 “课程号” ,以及 课程(课程号,课程名称) 表中保留了 课程号→课程名 函数依赖

分布式数据库

分片透明:是指用户不必关心数据是如何分片的,它们对数据的操作在全局关系上进行,即如何分片对用户是透明的。
- 水平分片
- 垂直分片
- 混合分片
复制透明:用户不用关心数据库在网络中各个节点的复制情况,被复制的数据的更新都由系统自动完成。
位置透明:是指用户不必知道所操作的数据放在何处,即数据分配到哪个或哪些站点存储对用户是透明的
局部映像透明性(逻辑透明):是最低层次的透明性,该透明性提供数据到局部数据库的映像,即用户不必关心局部DBMS支持哪种数据模型、使用哪种数据操纵语言,数据模型和操纵语言的转换是由系统完成的。因此,局部映像透明性对异构型和同构异质的分布式数据库系统是非常重要的。
事务提交的两个阶段
表决阶段,目的是形成一个共同的决定 ,
执行阶段,目的是实现这个协调者的决定
两条全局提交规则
- 只要有一个参与者撒销事务,协调者就必须做出全局撤销决定
- 只有所有参与者都同意提交事务,协调者才能做出全局提交决定
数据库分片
是将大数据表分解为较小的表(称为分片)的过程,这些分片分布在多个数据库集群节点上
- 水平分片 —— 按元组划分
- 垂直分片 —— 按属性划分
- 混合分片 —— 水平分片 + 垂直分片
优点:
提高系统的性能和可扩展性,将一个大型数据库拆分成多个小的数据库实例,每个实例只负责一部分数据的存储和查询,可以减少单个数据库的压力
能降低宕机的影响,从而使应用更加稳定
缺点:
数据一致性问题
由于数据被分散存储在多个分片中,因此在进行数据更新时,需要保证所有相关的分片中的数据都被更新,否则会导致数据不一致的问题。这需要引入复杂的分布式事务处理机制来保证数据的一致性,增加了系统的复杂度和开发难度。
查询跨分片性能问题
当一个查询需要跨越多个分片时,需要将查询请求发送到每个分片并合并结果,这会增加查询的响应时间和复杂度。
分片规则设计问题
分片规则的设计需要考虑到数据均衡、分片数量、容错能力等因素,如果设计不合理会导致数据倾斜、性能瓶颈等问题。
分片管理问题
由于系统中存在多个分片,需要对每个分片进行管理和维护,包括备份、恢复、监控、负载均衡等工作,这增加了系统的管理和维护成本。
分布式理论
CAP
- 一致性 ( Consistency )
- CAP 理论中的一致性是指强一致性。所有数据库节点在任意时间的数据都是完全一致
- 可用性 ( Availability )
- 服务一直可用,能够响应客户端的读写请求
- 分区容错性 ( Partition tolerance )
- 由于分布式系统通过网络进行通信,网络是不可靠的。当任意数量的消息丢失或延迟到达时,系统仍会继续提供服务,不会挂掉
CA | 优先保证一致性和可用性,放弃分区容错。 缺点:不再是分布式系统 |
CP | 优先保证一致性和分区容错性,放弃可用性。 缺点:牺牲用户体验 |
AP | 优先保证可用性和分区容错性,放弃一致性。 缺点:全局数据的不一致性 |
BASE理论
- Basically Available(基本可用)
- 分布式系统在出现故障时,允许损失部分可用性,即保证核心可用。
- Eventually consistent(最终一致性)
- 系统中所有的数据副本,在经过一段时间的同步后,最终能够达到一个一致的状态。
- Soft state(软状态)
- 状态可以有一段时间不同步。
硬状态 :数据库状态必须一直保持数据库一致性。
分布式事务解决方案
两阶段提交(2PC)
A节点是事务的协调者,B和C是事务的参与者。
第一阶段:投票阶段

1.事务询问 协调者 向所有的 参与者 发送事务预处理请求,称之为Prepare,并开始等待各 参与者 的响应。
2.执行本地事务 各个 参与者 节点执行本地事务操作,但在执行完成后并不会真正提交数据库本地事务,而是先向 协调者 报告说:“我这边可以处理了/我这边不能处理”。.
3.各参与者向协调者反馈事务询问的响应 如果 参与者 成功执行了事务操作,那么就反馈给协调者 Yes 响应,表示事务可以执行,如果没有 参与者 成功执行事务,那么就反馈给协调者 No 响应,表示事务不可以执行。
第一阶段执行完后,会有两种可能。1、所有都返回Yes. 2、有一个或者多个返回No。
**第二阶段:提交/执行阶段 ** (成功流程)
成功条件:所有参与者都返回Yes。

1.所有的参与者反馈给协调者的信息都是Yes,那么就会执行事务提交 协调者 向 所有参与者 节点发出Commit请求.
2.事务提交 参与者 收到Commit请求之后,就会正式执行本地事务Commit操作,并在完成提交之后释放整个事务执行期间占用的事务资源。
第二阶段:提交/执行阶段(异常流程)
异常条件:任何一个 参与者 向 协调者 反馈了 No 响应,或者等待超时之后,协调者尚未收到所有参与者的反馈响应。

1.发送回滚请求 协调者 向所有参与者节点发出 RoollBack 请求.
2.事务回滚 参与者 接收到RoollBack请求后,会回滚本地事务。
存在的问题
单点故障 :一旦事务管理器(协调者)出现故障,整个系统不可用
性能问题 参与者进行本地事务提交后才会释放资源,不适合高并发的场景
数据不一致 在阶段二,如果事务管理器发送 commit 消息,此时网络发生异常,那么只有部分参与者接收到 commit 消息,也就是说只有部分参与者提交了事务,使得系统数据不一致。
三阶段提交(3PC)
与两阶段提交不同的是,三阶段提交有两个改动点。
- 引入超时机制之外,
- 把2PC的准备阶段再次一分为二,这样三阶段提交就有CanCommit、PreCommit、DoCommit三个阶段。
1、CanCommit阶段

这阶段主要分为2步
- 事务询问 协调者 向 参与者 发送CanCommit请求。询问是否可以执行事务提交操作。然后开始等待 参与者 的响应。
- 响应反馈 参与者 接到CanCommit请求之后,正常情况下,如果其自身认为可以顺利执行事务,则返回Yes响应,并进入预备状态。否则反馈No
2、PreCommit阶段
在阶段一中,如果所有的参与者都返回Yes的话,那么就会进入PreCommit阶段进行事务预提交。这里的PreCommit阶段 跟上面的第一阶段是差不多的,只不过这里 协调者和参与者都引入了超时机制 (2PC中只有协调者可以超时,参与者没有超时机制)。
参与者在长时间无法与协调者节点通讯(协调者挂掉了)的情况下,会自动进行本地commit从而进行释放资源
3、DoCommit阶段
这里跟2pc的阶段二是差不多的
反规范化
规范化设计后,数据库设计者希望牺牲部分规范化来提高性能,这种从规范化设计的回退方法称为反规范化技术。
优点
- 提高查询性能:通过减少连接操作和数据表的归一化,反规范化可以降低查询的复杂度,从而提高性能。
- 减少查询时间:由于数据冗余的减少,查询操作所需的时间也会减少。
- 减少表之间的连接操作,提高数据库操作性能
缺点
- 数据冗余:反规范化引入了冗余数据,需要更大存储空间。
- 可能导致更新异常 ,产生数据不一致性:由于数据冗余,当对数据进行更新(增删改)操作时,需要确保所有冗余数据的一致性。
- 可维护性下降:反规范化增加了数据库设计的复杂性,并且可能导致更难以理解和维护的数据模型 , 更新和插入代码更加难写
技术手段
增加派生性冗余列 增加的列可以通过表中其他数据计算生成。它的作用是在查询时减少计算量,从而加快查询速度
增加冗余列 为了查询时避免连接操作,增加额外的列
重新组表 如果需要多次查看两个表连接出来的结果数据,则把这两个表重新组成一个表来减少连接而提高性能
分割表
- 水平分割 : 根据一行或多行数据的值把数据行放到两个独立的表中。
- 垂直分割:把主码和一些列放到一个表,然后把主码和另外的列放到另一个表中
水平分割通常在下面的情况下使用
- 表很大,分割后可以降低在查询时需要读的数据和索引的页数,同时也降低了索引的层数,提高查询速度。
- 表中的数据本来就有独立性,例如表中分别记录各个地区的数据或不同时期的数据,特别是有些数据常用,而另外一些数据不常用
- 需要把数据存放到多个介质上。
垂直分割的使用场景
如果一个表中某些列常用,而另外一些列不常用,则可以采用垂直分割
垂直分割可以使得数据行变小,一个数据页就能存放更多的数据,在查询时就会减少I/O次数。
其缺点是需要管理冗余列,查询所有数据需要join操作。
反规范技术如何维护数据的一致性:
常用的方法是批处理维护、应用逻辑和触发器。
批处理维护是指对复制列或派生列的修改积累一定的时间后,运行一批处理作业或存储过程对复制或派生列进行修改,这只能在对实时性要求不高的情况下使用。
应用逻辑 这就要求必须在同一事务中对所有涉及的表进行增、删、改操作。用应用逻辑来实现数据的完整性风险较大,因为同一逻辑必须在所有的应用中使用和维护,容易遗漏,特别是在需求变化时,不易于维护。
触发器,对数据的任何修改立即触发对复制列或派生列的相应修改。触发器是实时的,而且相应的处理逻辑只在一个地方出现,易于维护。一般来说,是解决这类问题的最好的办法。
事务机制保证
存储异常的问题:
数据冗余:如果某门课程有100个学生选修,那么在R的关系中就要出现100个元组,这门课程的任课教师姓名和地址也随之重复出现100次。
修改异常:由于上述冗余问题,当需要修改这个教师的地址时,就要修改100个元组中的地址值,否则就会出现地址值不一致的现象。
插入异常:如果不知道听课学生名单,这个教师的任课情况和家庭地址就无法进入数据库;否则就要在学生姓名处插入空值。
删除异常:如果某门课程的任课教师要更改,那么原来任课教师的地址将随之丢失
数据库索引
提升查询效率,降低添加、修改、删除效率。采用B树,B+树等。
主从复制
主从复制,是用来建立一个和主数据库完全一样的数据库环境,称为从数据库。这样做的好处是:
- 做数据的热备。作为后备数据库,主数据库服务器故障后,可切换到从数据库继续工作,避免数据丢失。
- 架构的扩展。业务量越来越大,1/0访问频率过高,单机无法满足,此时做多库的存储,降低磁盘1/0访问的频率,提高单个机器的1/0性能。
- 读写分离。使数据库能支持更大的并发。
mysql 主从复制步骤
master(binlog dump thread)
主要负责Master库中有数据更新的时候,会把日志信息写入到主库的binlog
文件中。创建log dump
线程通知Slave主库中存在数据更新- Slave中创建 I/O thread , 向 master 服务器请求 binary log。master 会返回更新的 binary log 。Slave将binlog保存在 relay log(中继日志) 。
- 当Slave检测到中继日志有更新,( SQL线程)就会将更新的内容同步到Slave数据库中
binlog有三种模式:
基于SQL语句的复制。每一条更新的语句(insert、update、delete)都会记录在binlog中,进而同步到从库的relaylog中,被从库的SQL线程取出来,回放执行
- binlog的日志量可能会比较少 ( 如一个涉及行数为1000行的update语句:同步这一个语句,就同步了1000行的数据 )
- SQL语句里如果含有绑定本地变量的函数、关键字时,可能造成主从不一致的情况。比如SQL语句中有time函数
基于行的复制,不记录SQL语句,只记录了哪个记录更新前和更新后的数据,可以保证主从之间数据绝对相同
混合复制:以上两种模式的混合,选取两者的优点
mysql主从同步的同步模式:
全同步:当主库执行完一个事务,需要等待所有的从库都执行了该事务,才返回给客户端
- 数据安全性最高,只要不是所有数据库都发生异常,就能保证数据不丢失。
- 缺点是:因为需要等待所有从库执行完该事务才能返回,所以全同步复制的性能必然会收到严重的影响。
半同步:当主库执行完一个事务。主库只需要等待至少一个从库节点从 Binlog 中收到该请求,并保存到 Relay Log 文件即可,主库不需要等待所有从库给主库反馈。
只收到的一个反馈,而不是全部从库完成提交的反馈,节省了很多时间,
能保证主库发生故障后,至少能从余下的1个从库上找回全部数据
权衡了数据安全性和性能
异步:主库在执行完事务后,会立即将结果返给给客户端,并不关心从库是否已经接收并处理
主库如果发生问题,此时主库已经提交的事务可能并没有同步到从库上。可能导致数据丢失或不完整。
处理请求的延迟降到了最低
数据库视图
视图是从一个或几个基本表(或视图)中导出的虚拟的表 。 在数据库中仅存放了视图的定义,不存放视图对应的数据。
优点
- 视图能简化用户的操作 。 经常使用的查询可以被定义为视图,用户直接查询视图便可得出所需数据,而不需要关注视图背后复杂的组成逻辑
- 视图机制可以使用户以不同的方式查询同一数据 。
- 视图对数据库重构提供了一定程度的逻辑独立性 : 可帮助用户屏蔽真实表结构变化带来的影响。如果进行添加新表或者在原有表上添加新字段,用户的应用程序不会受到影响
- 视图可以对机密的数据提供安全保护 : 可以防止未授权用户查看特定的行或列
物化视图:将视图的内容物理存储起来。同时当原始表中的数据更新时,物化视图也会更新。
分页分表分库
分区
指将一张表的数据拆分成多个区块 , 每个区块独立存储 , 但逻辑上还是只有一张表。
把一个逻辑表文件分成几个物理文件后进行存储
分区策略 | 分区方式 | 说 明 |
---|---|---|
范围分区 【RANGE】 | 按数据范围值来做分区 | 例:按用户编号分区,0-999999映射到分区A; 1000000-1999999映射到分区B。 |
散列分区 【HASH】 | 通过对key进行hash运算分区 | 例:可以把数据分配到不同分区,这类似于取余操 作,余数相同的,放在一个分区上。 |
列表分区 【LIST】 | 根据某字段的某个具体值进行分区 | 例:长沙用户分成一个区,北京用户一个区 |

分区的优点
1、相对于单个文件系统或是硬盘,分区可以存储更多的数据。分区的数据可以存放在不同的物理设备上,可以充分利用多个硬件设备
2、数据管理比较方便,比如要清理或废弃某年的数据,就可以直接删除该日期的分区数据即可。
3、精准定位分区查询数据,不需要全表扫描查询,大大提高数据检索效率。
4、可跨多个分区磁盘查询,来提高查询的吞吐量。
5、在涉及聚合函数查询时,可以很容易进行数据的合并。
分表
把一张表按一定的规则分解成多个具有独立存储空间的实体表。
水平分表 ( 行记录 ) , 垂直分表 (列记录 )
优点:
- 单表数据量太大,导致索引膨胀,查询耗时长,影响正常CRUD。
- 不受制于数据库规格约束,使用更为灵活。不要求使用相同的数据库引擎,只要能正确执行sql语句的数据库,不同厂商开发的数据库都可以使用 。
缺点:
1、需要额外的中间件进行代理(mycat),增加复杂度
2、统计全局数据需要跨表进行查询,性能下降
分库
什么情况下要分库:
1、需要存储超大数据,单个数据的处理能力有限。
垂直分库( 按业务功能 )
水平分库 ( 将单个库中的表作水平分表,然后将子表分别置于不同的子库当中,独立部署 )
缺点:
1、分布式事务
REDIS
分布式存储方案
分布式存储方案 | 核心特点 |
---|---|
主从(Master/Slave)模式 | 一 主(Master)多从( Slave ), Slave 会同步 Master 的更新,保持主从一致 故障时手动切换 |
哨兵(Sentinel)模式 | 有哨兵的一主多从,主节点故障自动选择新的主节点 |
集群(Cluster)模式 | 通过数据分片和分布式存储实现负载均衡和大规模数据存储。将数据分为 16384 个槽位,每个节点负责一部分槽位 |
Redis集群切片的常见方式
集群切片方式 | 核心特点 |
---|---|
客户端分片 | 在客户端通过key的hash值,计算出需要映射到哪一个Redis实例 |
代理分片 | 在应用软件和Redis中间,例如:Twemproxy、Codis等,由中间件 实现服务到后台Redis节点的路由分派。 |
服务端分片 | Redis Cluster模式 客户端可以和集群中任意Redis实例通信,当客户端访问某个实例时,服务器进行计算key应该映射到哪个具体的Redis实例中存储,如果映射的实例不是当前实例,则该实例主动引导客户端去对应实例对key进行操作。这其实是一个重定向的过程。这个过程不是从当前Redis实例转发到对应的Redis实例,而是客户端收到服务器通知具体映射的Redis实例 重定向到映射的实例中 |
Redis数据分片算法
分片方案 | 分片方式 | 说 明 |
---|---|---|
范围分片 | 按数据范围值来做分片 | 例:按用户编号分片,0-999999映射到实例A; 1000000-1999999映射到实例B。 |
哈希分片 | 通过对key进行hash运算分片 | 可以把数据分配到不同实例,这类似于取余操作,余 数相同的,放在一个实例上。 |
一致性哈希分片 | 哈希分片的改进 | 利于扩展结点,可以有效解决重新分配节点带来的无 法命中问题。 |
Redis数据类型
数据结构 | 使用场景 |
---|---|
String | 字符串结构(不光可以保存文本数据还可以保存二进制数据)。存储一些配置数据、缓存对象、数据统计、时间内限制请求次数 |
Hash | 键值对结构。用户信息、商品信息、文章信息、购物车信息 |
List | 列表结构。最新文章、最新动态,可用于实现消息队列等简单场景。 |
Set | 集合数据结构。(1)需要存放的数据不能重复的场景。网站 UV 统计(数据量巨大的场景还是 HyperLogLog更适合一些)、文章点赞、动态点赞等场景。(2)需要获取多个数据源交集、并集和差集的场景,共同好友(交集)、共同粉丝(交集)、共同关注(交集)、好友推荐(差集)、音乐推荐(差集)、订阅号推荐(差集+交集) 等。(3)需要随机获取数据源中的元素的场景。抽奖系统、随机点名等场景。 |
Zset | 有序集合数据结构。可用于各种排序场景。需要随机获取数据源中的元素根据某个权重进行排序的场景,各种排行榜比如直播间送礼物的排行榜、朋友圈的微信步数排行榜、王者荣耀中的段位排行榜、话题热度排行榜等等。 |
Bitmap | 二进制位。需要保存状态信息(0/1 即可表示)的场景。用户签到情况、活跃用户情况、用户行为统计(比如是否点赞过某个视频)。 |
HyperLogLog | 基数计数。数量量巨大(百万、千万级别以上)的计数场景。热门网站每日/每周/每月访问 ip 数统计、热门帖子 uv 统计。 |
Geospatial | 地理空间索引。需要管理使用地理空间数据的场景。附近的人。 |
内存淘汰算法
内存空间不够的时候采取的算法:
●volatile-lru->找出已经设置过期时间的数据集,将最近最少使用(被访问到)的数据干掉。
● volatile-ttl->找出已经设置过期时间的数据集,将即将过期的数据干掉。
● volatile-random->找出已经设置过期时间的数据集,进行无差别攻击,随机干掉数据。
● volatile-lfu->找出已经设置过期时间的数据集,将一段时间内,使用次数最少的数据干掉。
● allkeys-lru->与第1个差不多,数据集从设置过期时间数据变为全体数据。
● allkeys-lfu->与第4个差不多,数据集从设置过期时间数据变为全体数据。
allkeys-random->与第3个差不多,数据集从设置过期时间数据变为全体数据。
● no-enviction->什么都不干,报错,告诉你内存不足,这样的好处是可以保证数据不丢失 (默认)
过期策略
过期策略:定期删除 + 惰性删除
惰性删除:当访问Key时,才去判断它是否过期,如果过期,直接干掉。这种方式对CPU很友好,但是一个key 如果长期不用,一直存在内存里,会造成内存浪费。
定期删除:隔一段时间,依据一定的算法抽取一些设置了过期时间的key,检查其是否过期,如果有过期就删除。
定期删除 + 惰性删除存在的问题
如果某个key过期后,定期删除没删除成功,然后也没再次去请求key,也就是说惰性删除也没生效。这时,如果大量过期的key堆积在内存中,redis的内存会越来越高,导致redis的内存块耗尽。那么就应该采用内存淘汰机制。
持久化
RDB (Redis DataBase ) : 将redis中的数据以快照的方式存储到磁盘中。
1 |
|
AOF ( Append Only File ) :文件追加方式。把每条改变数据集的命令追加到AOF文件,这样出问题了,可以重新执行AOF文件中的命令来重建数据集。
RDB-AOF混合持久化
常见的问题
1、缓存雪崩
原因 :
- redis 故障 ( 主从复制提高可用性 , 使用cluster集群降低故障的影响范围 )
- 采用了相同的过期时间
现象:在某个时刻,redis中大量的key过期,大量的请求无法从缓存中查到数据,导致这些请求直接访问数据库,造成DB压力瞬间变大而宕机
解决方案:
- 1、使用锁或队列:保证不会有大量的线程对数据库一次性进行读写,从而避免失效时大量的并发请求落到底层存储系统上。
- 2、为key设置不同的缓存失效时间:在固定的一个缓存时间的基础上 + 随机一个时间作为缓存失效时间。
- 3、使用多级缓存:设置一个有时间限制的缓存 + 一个无时间限制的缓存。避免大规模访问数据库。
2、缓存穿透
缓存穿透:访问的key在redis里不存在。
原因
- 恶意攻击,造成大量访问Redis和数据库中都不存在的key
- 大量请求访问数据库里有但redis没有的key
解决方案:
1、 用户合法性校验 , 对用户的请求合法性进行校验,拦截恶意重复请求。
2、缓存空值。对查询结果为空的key也进行缓存
3、布隆过滤器:
将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被这个bitmap拦截掉,从而避免了对底层存储系统造成的查询压力。
- 作用:快速识别1个元素是否在一个集合中。
- 原理:通过一个长二进制向量和一系列随机映射函数(一般用多种hash算法来计算)来记录与识别某个数据是否在一个集合中。
- 优点:占用内存小、查询效率高、不需要存储元素本身
- 缺点:有一定的误判率、一般情况下不能从布隆过滤器中删除元素、不能获取元素本身
3、缓存击穿
热点的key设置了太短的过期时间。
解决方案:
设置较长的过期时间。非常重要的key,则设置永久有效
预热redis,运行一个批处理脚本,将可能会大量访问的数据预先加载到redis,业务再开张。
在最前端进行流量控制,逐步释放进来请求。给出一段时间,让redis逐步加载热数据。
redis 和 mysql主从一致性
(不能保证完全一致性)
1、先更新数据库,再更新缓存
2、先删缓存,再更新数据库
(最终一致性方案)
使用消息中间件( RocketMQ )
- 更新数据库中的数据
- 更新redis中的数据(失败)
- 把失败的请求写入消息中间件
- 异步重试,确保成功

使用Canal插件
- 监控mysql中的binlog日志
- 把更新的数据同步到redis

如果系统不希望出现数据的短期不一致,保证强一致性
1、采用读写锁的方式,在数据更新的时候,其他任何请求都无法访问缓存中的数据

ORM
ORM,即Object-Relational Mapping,它的作用就是在关系型数据库和对象之间做了一个映射。 ORM可以将数据库中的数据表映射为面向对象的类,通过面向对象的方式来操作数据库。这样我们在操作数据库的时候,不需要再去和复杂SQL打交道,只要像操作对象一样操作它就可以了
MyBatis 与 Hibernate 区别:
hibernate是全自动,而mybatis是半自动
- 通常开发者只需要定义好持久化对象到数据库表的映射关系,就可以通过Hibernate提供的方法完成持久层操作。开发者不需要编写SQL,并调用JDBC接口来执行,所以其开发效率会高于MyBatis
- 需要手动编写SQL语句,以及ResultMap
hibernate数据库移植性远大于mybatis
- hibernate 通过其强大的映射结构和hql语言,对主流厂商的数据库(Oracle、MySQL等)做了适配,开发者在开发过程中无需考虑各数据库之间的差异。可以跨数据库平台
- mybatis由于需要手写sql , 开发过程中需要考虑不同 数据库之间sql语句的差异。
sql直接优化上,mybatis要比hibernate方便很多
- hibernate的sql是自动生成的,无法直接维护sql
- MyBatis允许开发人员手动优化 SQL 语句,从而提高查询效率
数据仓库
数据仓库是一个面向主题的、集成的、相对稳定的、反映历史变化的数据集合,用 于支持管理决策
数据处理大致可以分成两大类,分别是联机事务处理( OLTP ) 和 OLAP
OLTP 是传统数据库的主要应用,支持基本的、日常的事 务处理;
OLAP 是数据仓库系统的主要应用,支持复杂的分析操作,侧重决策支持,并且提供直观易懂的查询结果
OLTP | OLAP | |
---|---|---|
用户 | 操作人员,低层管理人员 | 决策人员,高层管理人员 |
功能 | 日常操作处理 | 分析决策 |
DB设 计 | 面向应用 | 面向主题 |
数据 | 当前的、 最新的、细节的、二维的、 分立的 | 历史的、聚集的、多维的、集成的、统一的 |
存取 | 读/写数十条记录 | 读上百万条记录 |
工作单位 | 简单的事务 | 复杂的查询 |
用户数 | 多 | 少 |
DB 大小 | MB 或 GB 级 | GB 或 TB 级 |
补充
关系型数据库
瓶颈
无法满足数据高并发读写的需求。网站的用户并发性非常高,往往达到每秒上万次读写请求,对于传统关系型数据库来说,硬盘I/O是一个很大的瓶颈
无法满足海量数据的高效率读写 。网站每天产生的数据量是巨大的,对于关系型数据库来说,在一张包含海量数据的表中查询,效率是非常低的
横向扩展比较困难。因为需要考虑分布式事务处理
全文搜索功能弱。只能使用like 匹配关键字,效率低下。
维护索引付出的代价大 。 为了提高查询能力,通常热点表都会添加索引,数据的新增必然伴随着索引的新增。索引也会占用空间的。
数据类型表达能力差:关系数据模型不直接支持复杂的数据类型。 由于第一范式的要求,所有的数据必须转换为简单的类型,如整数、实数、双精度数和字符串。 面对复杂数据类型的就是需要额外地分解数据结构工作,这些被分解的结构不能直接表示应用数据,。
优点:
- 事务支持:关系型数据库支持ACID(原子性、一致性、隔离性和持久性)事务特性,可以确保数据的完整性和可靠性。这对于金融、电商等行业的应用尤为重要。
- 结构化存储:关系型数据库中的数据以表格的形式存储,这种结构化的 数据存储 方式使得数据的组织和管理更加规范和有序。
- 强大的查询功能。 关系型数据库还提供了一些高级查询功能,如连接查询、子查询、聚合函数等
- 数据稳定 。 数据持久化到磁盘,没有丢失数据风险,支持海量数据存储
NoSQL
特点:
数据模型比较灵活,NoSQL数据库不遵循关系模型 , 支持json、图片、文档等非结构化的数据类型。
高可用性。nosql从设计之初,就支持分布式架构。数据分布在多个服务器和区域中,因此没有单点故障。因此,NoSQL 数据库更加稳定和弹性,具有持续可用性和零停机时间
高性能 。NoSQL数据库通常采用内存存储和索引技术,以及并行计算和分布式计算技术,可以提供高性能的数据存储和查询能力
易于横向扩展。低成本
缺点:
- 没有标准化的语言。用于查询数据的语法因不同类型的 NoSQL 数据库而异
- 复杂查询效率低下。NoSQL数据库的查询能力相对较弱,通常只支持基本的查询操作。与传统关系型数据库相比,NoSQL数据库缺少复杂的查询操作和聚合函数。在需要进行复杂的数据查询和分析的场景中,NoSQL数据库的查询能力可能无法满足需求。
- 无法要求数据强一致性。不保证数据库的ACID的事务特性。大多数 NoSQL 数据库都遵循基本可用、软状态、最终一致性(BASE) 一致性模型。
OLTP、OLAP
OLTP 是传统数据库的主要应用,支持基本的、日常的事 务处理;
OLAP 是数据仓库系统的主要应用,支持复杂的分析操作,侧重决策支持,并且提供直观易懂的查询结果
OLTP | OLAP | |
---|---|---|
用户 | 操作人员,低层管理人员 | 决策人员,高层管理人员 |
功能 | 日常操作处理 | 分析决策 |
DB设 计 | 面向应用 | 面向主题 |
数据 | 当前的、 最新的、细节的、二维的、 分立的 | 历史的、聚集的、多维的、集成的、统一的 |
存取 | 读/写数十条记录 | 读上百万条记录 |
工作单位 | 简单的事务 | 复杂的查询 |
用户数 | 多 | 少 |
DB 大小 | MB 或 GB 级 | GB 或 TB 级 |
列式存储、行式存储
行式存储 :一行中的数据会连续存储在存储介质中
对数据进行插入 和修改操作很方便
查询时即使只涉及少数几项属性,也需要把该行数据所有内容都读取到内存中读取数据的时候硬盘寻址范围很大
空值也要占固定的空间
列式存储:一列中的数据会连续存储在存储介质中
数据压缩 。 列式存储的时候可以为每一列创建一个字典,存储的时候就仅存储数字编码即可,降低了存储空间需求
当仅查询个别列的时候,可以仅读取需要的那几个列 。 硬盘寻道范围小。
对每一列进行统计分析(投影操作)就很方便。
SELECT完成时,被选中的数据需要重新组装。
插入(INSERT)和修改(UPDATE)操作比较麻烦。
键值数据库 | 列式存储 | 文档型数据库 | 图数据库 | |
---|---|---|---|---|
主要产品 | redis 、 Memcached | HBase | MongoDB | Neo4j、OrientDB |
数据模型 | 键/值对 值可以是:String、Hash、Set、ZSet、List ( Redis ) 文本形式、二进制 ( Memcached ) |
列蔟 | 键/值对 值 是 文档 |
图结构 |
持久化 | 都是内存数据库 ( 将数据存放在内存中 ) redis 支持持久化 ( AOF 、RDB ) Memcached 不支持 |
底层存储基于 HDFS 实现 | 支持 | |
优点 | 1、数据基于内存、读写效率高 |
1、海量数据存储、数据压缩 2、横向扩展 |
1、数据结构灵活: 支持 JSON、XML等复杂数据结构 2、表结构容易扩展,扩展字段容易 |
1、强大的图形分析能力 2、适用于具有复杂关系的场景 |
缺点 | 1、不支持复杂的条件查询 | |||
事务支持 | 不支持 | 不严格ACID | 不支持事务操作 | 不支持 |
应用场景 | 缓存系统、会话管理、配置管理 | OLAP、日志分析、历史数据存储 | 内容管理系统(如CMS)、博客平台、API服务 | 社交网络、模式识别、依赖分析、推荐系统、路径计算 |