第一章 MySQL体系结构和存储引擎
1.1 定义数据库和实例
数据库 :物理操作系统文件或其他形式类型文件的集合
实例 : MySQL数据库由后台线程以及一个共享内存区组成。
Mysql数据库实例在系统上的表现就是一个进程
1.2 Mysql体系接口
- 连接池组件
- 管理服务和工具组件
- SQL接口组件
- 查询分析器组件
- 优化器组件
- 缓冲组件
- 插件时存储引擎
- 物理文件
1.3 InnoBD存储引擎
InnoDB存储引擎支持事务,其设计目标主要是面向在线事务处理OLTP,特点是行锁设计、支持外键并支持类似于Oracle的非锁定读
通过使用MVCC(多版本并发控制)实现了高并发行,并且实现了SQL标准的4中隔离级别
默认为Repeatable级别,同时适应next-key locking的策略来避免幻读
1.5 链接MySQL
连接MySQL操作是一个连接进程和MySQL数据库实例进行通信,从程序设计的角度来说,本质上是进程通信。
- 管道
- 命名管道
- 命名字
- TCP/IP套接字
- UNIX套接字
第二章 INnoDB存储引擎
2.1 InnoDB存储引擎概述
特点是 行锁设计、支持MVCC、支持外键、提供一致性非锁定读同时被设计用来最有效地利用及使用内存和CPU
## 2.3 InnoDB体系结构
Innodb存储引擎有多个内存块,可以认为这些内存块组成了一个大的内存池
- 维护所有进程/线程需要访问的多个内部数据结构
- 缓存磁盘上的数据,方便快速读取,同时在对磁盘文件的数据修改之前在这里缓存
- 重做日志(Redo log)缓冲
### 2.3.1 后台线程
#### 1 Master Thread
主要负责将缓冲之中的数据几步刷新到磁盘,保证数据一致性、包括脏页的刷新、合并插入缓冲(Insert Buffer)、UnDO页回收等
2 IO Thread
InnoDB存储在引擎中大量使用了AIO处理IO写请求,IO thread 主要是负责这些IO请求的回调
3 Purge Thread
Purge Thread 来回收已经使用并分配的undo页
4 Page Cleaner Thread
其作用是将之前盘本中的脏页刷新操作单独放入到一个线线程中来完成,减轻Master Thread 的工作
2.3.2 内存
1 缓冲池
对于数据库中页的修改,首先修改在缓冲池中的页,然后以一定的频率刷新到磁盘上。这需要注意的是,页从缓冲池刷新回磁盘的操作并不是在每次页发生更新时出发,而时通过一种CheckPoint的机制刷新回磁盘。
缓冲之中的数据页类型由:
- 索引页
- 数据页
- undo页
- 插入缓冲
- 自适应哈希索引
- InnoDB存储的锁信息
- 数据字典
2 LRU list /Free List / FLush List
LRU list 用来管理缓冲池中页的可用性
FLush list 用来管理将页刷新回磁盘
3 重做日志缓冲
- Master Thread 每秒会将重做日志缓冲刷新到重做日志文件
- 每个事务提交时会将重做日志缓冲刷新到重做日志文件中
- 重做日志缓冲池剩余1/2时,重做日志缓冲会刷新到日志文件中
4 额外的内存池
2.4 Checkpoint
为了避免数据丢失问题,当前事务数据库系统普遍都采用了 Write Ahead Log策略,即当事务提交时,先写重做日志,再修改页。当由于发生宕机而导致数据丢失时,通过重做日志来完成数据恢复,这也是事务ACID中的D的要求
CheckPoint技术的目的:
- 缩短数据库的恢复时间
- 缓冲池不够用时,将脏页刷新到磁盘
- 重做日志不可用时,刷新脏页
InnoDB存储引擎内部由两种Checkpoint
- Sharp Checkpoint
- Fuzzy Checkpoint
Sharp Checkpoint 发生在数据库关闭时,将所有的脏页都刷新回磁盘,时默认的工作方式 innodb_fast_shutdown=1
Fuzzy Checkpoint 即之刷新一部分脏页,而不是刷新所有的脏页
2.5 Master Thread工作方式
InnoDB存储引擎的主要工作都是在一个单独的后台线程Master Thread
具有最高的线程优先级,其内部由多个循环组成
2.6 InnoDB关键特性
- 插入缓冲
- 两次写
- 自适应哈希索引
- 异步I/O
- 刷新邻接页
2.6.1 Insert Buffer
Insert Buffer
对于非聚集索引的插入或更新操作,不是每一次直接插入到索引页,而时先做判断,插入的非聚集索引是否在缓冲池中,若再,则直接插入;若不在,则先放入到一个Insert Buffer中。然后再以一定的频率进行Insert Buffer和辅助索引子节点的merge,这时通常能将多个插入合并到一个操作中,这就大大提高了对于非聚集索引插入的性能
Insert buffer 的使用需要同时满足以下条件
- 索引时辅助主索引
- 索引不是唯一的
辅助索引不是能是唯一的,因为再插入缓冲时,数据库并不去查找索引页来判断记录的唯一性。如果去查找,则又会发生离散读取,从而导致Insert Buffer 失去了意义。
Change Buffer
InnoDB 对DML操作 Insert、Delete、Update都进行缓冲,他们分别是 Insert Buffer 、 Delete Buffer、 Purge buffer
Insert Buffer 的内部实现
Insert Buffer 的数据结构是一个棵B+树,负责对所有的表的辅助索引进行Insert Buffer, 而这棵B+树存放在共享表空间。
2.6.2 两次写 double write
设想: 如果出现写失效,可以通过重做日志进行恢复。 但是重做日志是对页的物理操作。如果这个页本身已经发生了损坏,对其进行重做是没有意义的。
即 再应用重做日志之前,用户需要一个页的副本, 当写入失效时,先通过页的副本来还原该页,再进行重做。
doublewrite由两部分组成,一部分时内存中的 doublewrite buffer ,大小为2MB,另一部分时物理磁盘空间上的连续128个页,即2个区。大小同为2MB
对缓冲池的脏页进行刷新时,并不直接写到磁盘上,而时会通过memcpy函数将脏页先复制到内存中的doublewrite buffer,之后通过doublewrite buffer再分两次,每次1MB的顺序写入共享表空间的物理磁盘上,然后马上调用fsync函数,同步磁盘。
如果操作系统再将页写入磁盘的过程中发生了崩溃,在恢复过程中,InnoDB存储引擎可以从共享表空间中的doublewrite中找到该页的一个副本,将其复制到表空间文件,在应用重做日志。
2.6.3 自适应哈希
InnoDb存储引擎会自动根据访问频率和模式来自动为某些热点页建立哈希索引。
2.6.4 异步IO
2.6.4 刷新邻接页
第三章 文件
3.1 参数文件
3.2 日志文件
- 错误日志
- 二进制日志
- 慢查询日志
- 查询日志
3.2.1 错误日志
show variables like 'log_error'
3.2.2 慢查询日志
long_query_time 设置慢查询阈值
可以通过 long_query_time 设置慢查询时间
SHOW VARIABLES LIKE 'long_query_time'\G
3.2.3 查询日志
3.2.4 二进制日志
binlog
记录了对mysql数据库执行的所有更新操作 -----------databus 监听 binlog
二进制日志主要的作用是:
- 恢复
- 复制
- 审计
二进制日志配置相关参数
- max_binlog_size
- binlog_cache_size
- sync_binlog
- binlog_do_db
- binlog_ignore_db
- log_slave-update
- binlog_format
sync_binlog : 控制写入到磁盘的频率
- 0 : sync_binlog 默认位0,表
- 1 : 表示采用同步方写磁盘的方式来写二进制日志,不使用缓冲来写二进制日志
即使将sync_binlog设为1,还是会有一种情况导致问题发生。 当使用InnoDB存储引擎是,在一个事务发出commit动作之前,由于sync_binlog位1,因此会将二进制日志立即写入磁盘。如果这是已经写入了二进制日志,但是提交还没有发生,并且此时发生了宕机,那么再MySQL数据库下次启动时,由于COMMIT操作并没有发生,这个事务会被回滚掉。但是二进制日志已经记录了该事务信息,不能被回滚。这个问题可以通过将参数innodb_support_xa设为1来解决。
innodb_support_xa可以开关InnoDB的xa两段式事务提交。
innodb_support_xa可以开关InnoDB的xa两段式事务提交。
如何开启?
innodb_support_xa=true,支持xa两段式事务提交。
默认为true,值为on,多线程并发执行提交事务,按照事务的先后顺序写入binlog,如果关闭则binlog记录事务的顺序可能与实际不符,造成slave不一致
mysql> show global variables like 'innodb_support_xa';
+-------------------+-------+
| Variable_name | Value |
+-------------------+-------+
| innodb_support_xa | ON |
+-------------------+-------+
1 row in set (0.01 sec)
内部XA
现在mysql内部一个处理流程大概是这样:
1. prepare ,然后将redo log持久化到磁盘
2. 如果前面prepare成功,那么再继续将事务日志持久化到binlog
3. 如果前面成功,那么在redo log里面写上一个commit记录
那么假如在进行着三步时有任何一步失败,crash recovery是怎么进行的呢?
此时会先从redo log将最近一个检查点开始的事务读出来,然后参考binlog里面的事务进行恢复。
如果是在1 crash,那么自然整个事务都回滚;
如果是在2 crash,那么也会整个事务回滚;
如果是在3 crash(仅仅是commit记录没写成功),那么没有关系因为2中已经记录了此次事务的binlog,所以将这个进行commit。所以总结起来就是redo log里凡是prepare成功,但commit失败的事务都会先去binlog查找判断其是否存在(通过XID进行判断,是不是经常在binlog里面看到Xid=xxxx?这就是xa事务id),如果有则将这个事务commit,否则rollback。
3.3 套接字文件
3.4 pid文件
3.5 表结构定义文件
3.6 InnoDB存储引擎文件
3.6.1 表空间文件
InnoDB采用将存储的数据按表空间进行存放的设计,再默认配置下会有一个初始大小位10MB,ibdata1的文件。
可通过 innodb_data_file_pate进行设置
例如:
innodb_data_file_path = /db/ibdata1:2000M;/dr2/db/idata2:2000M:autoextend
单独表空间进存储每个表的数据、索引和插入缓冲BITMAP等信息,其余信息还是存放在默认的表空间中
3.6.2 重做日志文件
重做日志记录了InnoDB存储引擎的事务日志
当实例或介质失败,使用重做日志可以恢复到掉电前的时刻。
影响重做日志的属性
- innodb_log_file_size
- innodb_log_files_in_group
- innodb_mirrored_log_groups
- innodb_log_group_home_dir
二进制日志和重做日志的区别
- Innodb 二进制日志文件记录的是该日志的逻辑日志
重做日志记录的是每个页更改的物理情况 - 写入时间不同, 二进制日志文件仅再事务提交前进行提交,即只写磁盘一次
而再事务进行过程中,却不断有重做日志条目写入重做日志文件的写入不是直接写,而时先写入一个日志缓冲,然后按一定的条件顺序写入日志文件
重做日志缓冲往磁盘写入时,时按照512字节,也就是一个扇区的大小,是写入的最小单位,因此可以保证写入必定是成功的。
已知道主线程会每秒将重做日志缓冲写入磁盘。
另一个出发写磁盘的参数 innodb_flush_log_at_trx_commit
- 0:事务提交时并不写入,等待主线程刷新
- 1:表示再执行commit时将重做日志缓冲同步写入到磁盘即版友fsync调用
- 2:表示将重做日志一部写道磁盘,即写到文件系统。不能完全保证再执行commit时肯定会写入重做日志
第四章 表
4.1 索引组织表
InnoDB存储引擎中,表都是根据主键顺序组织存放的,这种存储方式的表成为索引组织表
4.2 InnoDB逻辑存储结构
所有数据逻辑的存放在表空间中,表由段(SEGMENT)\区(extet)页(page)组成
4.2.1 表空间
如果启用了 innodb_file_per_table,每张表的表空间只存放的是数据、索引和插入缓冲Bitmap页,其他数据,如回滚信息、插入缓冲、索引页、系统事务信息、二次写缓冲还是存放在原来的共享表中
4.2.2 段
- 数据段
- 索引段
- 回滚段
数据段即B+树的叶子节点,索引段即索引节点
4.3.2 区
区是连续的页组成的,每个区大小都为1MB,默认情况InnoDB存储引擎页大小位16KB,一个区由64个连续的页
4.2.4 页
页是InnoDB磁盘管理的最小单位
- 数据页(B tree node)
- undo 页
- 系统页
- 事务数据页
- 插入缓冲位图页
- 插入缓冲空闲列表页
- 未压缩的二进制大对象页
- 压缩的二进制大对象页
4.2.5 行
4.4 InnoDB数据页结构
- File Header
- Page Header
- Infimun /Supremum Records
- User Recored
- Free Space
- Page Directory
- File Trailer
4.5 约束
InnoDB数据完整性的约束
- Primary Key
- Unique Key
- Foreign Key
- Default
- Not Null
约束与索引的区别: 约束更多是一个逻辑概念,用来保证数据的完整性。索引是一个数据概念,也有逻辑上的概念,在数据库中还代表着物理存储的方式
外键
虽然外键能起到很好的约束作用,但是数据导入的操作,外键往往导致再外键约束上花费大量时间。
第五章 索引与算法
- B+树索引
- 全文索引
- 哈希索引
5.2 数据结构与算法
- 二分查找法
- 平衡二叉树
5.3 B+树
B+树是位磁盘或娶她直接存取辅助设备设计的一种平衡二叉树,在B+树中,所有记录节点都是按键值大小顺序粗放囊在同一层的叶子节点上。由各叶子节点指针进行连接。
5.3.1 B+树插入操作
leaf page 满 | index page 满 | 操作 |
No | No | 直接将记录插入到叶子节点 |
yes | no | (1)拆分leaf page(2)将中间节点放到Indexpage(3)小于中间节点的记录放在左边(4)大于或等于中间节点的记录放在右边 |
yes | yes | 1)拆分leaf page 2)小于中间节点的记录放在左边 3)大于或等于中间节点的记录放在右边 4)拆分index page 5)小于中间节点的记录放在左边 6)大于中间节点的记录放在右边 7)中间节点放入上一层index page |
B+树同样提供了类似于平衡二叉树的旋转功能:
旋转发生在leaf page已经满了, 但是其左右兄弟节点没有满的情况下。
5.3.2 B+树的删除操作
叶子节点小于填充因子 | 中间节点小于填充因子 | 操作 |
No | No | 直接将记录从叶子节点删除,如果该节点还是Index page节点,用该节点右节点代替 |
Yes | No | 合并叶子节点和它的兄弟节点,同时更新Index page |
Yes | Yes | 1)合并叶子节点和它的兄弟节点 2)更新Index Page 3)合并Indexpage 和他的兄弟节点 |
5.4 B+树索引
本质就是B+树在数据库中的实现。但是B+树在数据库中的特点是高扇出性。 高度一般在2-3层
分为聚集索引/辅助索引 区别是:叶子节点存放着的是不是一整行信息
5.4.1聚集索引
聚集索引就是按照每张表的主键构造一棵B+树,同时叶子节点中存放的即位整张表的行记录数据。也将聚集索引的叶子节点成为数据页。聚己所欲i你的这个特性决定了索引组织表中数据也是索引一部分。
聚集索引是逻辑上连续的。
5.4.2 辅助索引
叶子节点并不包含行记录的全部数据。叶子节点除了包含键值意外,每个节点中的索引行还包含了一个数千,该数千告诉存储引擎哪里可以找到与索引相对应的数据行。
堆表
:行数据按照插入顺序存放。堆表的特性决定了堆表的索引都是非聚集的。主键与非主键的区别在于是否为空。
5.4.3 B+树索引的分裂
5.4.4 B+树索引的管理
1、 索引管理
- Alter table
- create/ Drop Index
通过 SHOW INDEX FROM 可以观察到表上的索引信息
Cardinality 表示索引中为唯一值数目的估计值, Cardinality/表的行数应该尽可能接近1
优化器会根据这个值来判断是否使用这个索引。但是并不是实时更新的。
5.6 B+树索引的使用
5.6.1
- OLTP
- OLAP
5.6.2 联合索引
指对表上的多个列进行索引
最左匹配
5.6.3 覆盖索引
covering index
即从辅助索引中可以查询到记录
5.6.4不适用索引的情况
多发生于范围查找、join链表操作
例如
用户查询整行的数据,但是辅助索引不能够覆盖所要查询的信息。辅助索引查询到指定数据后,还需要一次书签访问来查找整行信息。虽然辅助索引的数据是顺序存放的,凡是进行书签查找的顺序是离散的。变成了磁盘上的离散读操作。如果访问量很大的时候,会选择通过聚集索引查找(表扫描)
5.7 哈希算法
5.7.1 哈希表
由直接寻址表改进而来
基于哈希函数,计算出关键字K的槽位。
哈希碰撞:如果两个关键字映射到同一个槽位上的形况
- 解决办法:链地址法
5.8 全文检索
5.8.2 倒排索引
- inverted file index 表现形式 {单词,单词所在文档}
- full inverted index 表现形式 {单词,(单词所在文档,在文档的具体位置)}
FTS?
红黑树?
ES?
第六章 锁
InnoDB存储引擎不需要锁升级,因为一个锁和多个锁的开销是相同的
6.1 什么是锁
锁机制用域管理共享资源的并发访问
提供数据的完整性和一致性
Innodb提供了一致性的非锁定读和行级锁支持
6.2 lock 与latch
latch 闩锁, 在InnoDB中,Latch又可分为mutex和rwLock, 目的是用来保证并发线程操作临界资源的正确性,并且通产没有死锁检测
lock的对象是事务,用来锁定的是数据库中的对象,如表、页、行。并且一般lock的对象仅在事务commit或rollback后进行释放。且有死锁机制
lock | latch | |
对象 | 事务 | 线程 |
保护 | 数据库内容 | 内存数据结构 |
持续时间 | 整个事务过程 | 临界资源 |
模式 | 行锁、表锁、意向锁 | 读写锁、互斥量 |
死锁 | 通过 wait-for grouph、time out 等级制进行死锁检测 | 五死锁检测机制,仅通过应用程序加锁的顺序(lock leveling)保证无死锁 |
存在于 | Lock Manager的哈希表中 | 在每个数据结构的对象中 |
6.3 InnoDB存储引擎中的锁
6.3.1 锁的类型
- 共享锁 S Lock
- 排他锁 X Lock
X | S | |
X | No | Yes |
S | No | yes |
InnoDB 支持多粒度锁定。为了支持在不同粒度上进行加锁操作,InnoDB支持意向锁意向锁
:将锁定对象分为多个层次,意向锁意味着事务希望更细粒度上进行加锁。
意向锁设计的主要目的是为了在一个事务中揭示下一行将被请求的所得类型。
由于InnoDB存储引擎支持的是行级别的锁,因此意向锁其实不会阻塞除全表扫描意外的任何请求。
IS | IX | S | X | |
IS | Y | Y | Y | N |
IX | Y | Y | N | N |
S | Y | N | S | N |
X | N | N | N | N |
6.3.2 一致性非锁定读
consitent nonlocking read
是指InnoDB存储引擎通过行多版本控制的方式读取当前执行时间数据库中行的数据通过undo段来完成
在InnoDB存储引擎的默认设置下,是默认的读取方式,即读取不会占用和等待表上的锁。但是在不同事务隔离级别下读取方式不同。并不是在每个事务隔离级别下都采用非锁定读。
在事务隔离级别Read Committed和Repeateble Read下,InnoDB会采用非锁定一致性读。但是对于快照的定义不同
- Read Committed事务隔离级别下:对于快照数据,非一致性读总是读取被锁定行的最新一份快照数据
- Repeateble Read事务隔离级别下:对于快照数据,非一致性读总是读取事务开始时的行数据版本
6.3.3 一致性锁定读
- select …… for update
- select …… lock in share mode
两者必须在同一个事务中
6.3.4 自增长与锁
auto inc locking
6.4 锁的算法
6.4.1 行锁的三种算法
- Record Lock : 单个行记录上锁
- Gap Lock:间隙锁,锁定一个范围,但不包含记录本身
- Nexk Key Lock: Gap Lock + Record Lock
Next key Lock 算法是为了解决Phantom Problem
当查询索引属含有唯一属性时,InnoDB存储引擎会对Next Key Lock 进行优化, 将其降级为 Record Lock,仅所著索引本身而不是范围。
Gap Lock的作用是为了组织多个事务将进路插入到同一个范围内。
用户可以通过以下方式显示关闭GapLock
- 将事务的隔离级别设置为Read Committed
- 将参数 innodb locks unsafe for binlog 设置为1
上述配置破坏了事务的隔离性, 并且对于replication 可能会导致主从数据不一致
6.4.2 解决Phantom Problem
在 Repeatable Read 下 InnoDB 采用next key locking 的机制避免幻读(Phantom Problem)
Phantom problem 是指在同一事务下,连续执行两次同样的SQL语句可能导致不同的结果,第二次SQL语句可能会返回之前不存在的行。
InnoDB 存储引擎默认的事务隔离界别是 Repeatable Read
在事务隔离级别是 Read Committed时仅采用Record Lock
6.5 锁问题。
6.5.1 脏读
脏读和脏页时两种概念。
脏页是值在缓冲池中已经被修改的页但还没有刷新到磁盘中
脏数据是指事务对缓冲池中的行记录的修改,并且还没有被提交,并且还没有提交
6.5.2 不可重复读
不可重复读是指在一个事务内多次读取同一数据集合。在这个事务还没有结束时,另外一个事务也访问同一数据集合,并做了一些DML操作。因此,在第一个事务中的两次读数据之间,由于第二个事务的修改,那么第一个事务两次读取道德情况不同
即幻读现象
InnoDB中通过Next Key Lock算法来避免不可重复读
6.5.3 丢失更新
简单来说就是一个事务的更新操作会被另一个事务的更新操作锁覆盖,从而导致数据的不一致
1) 事务T1将记录r更新为v1, 但是事务T1并未提交
2) 于此同时 事务T2将记录更新为v2,并未提交
3) T1提交
4) T2提交
虽然数据库能阻止丢失更新问题的产生,但是在生产应用中还有另一个逻辑意义的丢失更新,而导致该问题的并不是数据库本身的问题
1)事务T1查询一行数据,放入本地内存,并显示给中断用户user1
2)事务T2也查询到该行数据,并将取得的数据显示给终端用户user2
3)User1修改这行记录,更新数据库并提交
4)User2修改这行记录,更新数据库并提交
避免丢失更新的产生,需要让这个事务在串行化进行吗,而不是并行。
6.6 阻塞
在innodb_lock_wait_timeout用来控制等待的时间
innodb_rollback_on_timeout用来设定是否在等待超时时对进行中的事务进行回滚操作
6.7 死锁
死锁是指两个或两个以上的事务在执行过程中,因争夺锁资源而造成的一种互相等待的现象。
解决超时的办法:
- 超时机制
wait-for-graph 等待图 来检测死锁
- 锁的信息链表
- 事务等待链表
6.8 锁升级
第七章 事务
ACID
A 原子性 atomic
是指整个事务时不可分割的工作单位
C 一致性 consistency
在事务开始之前和事务结束之后,数据库的完整性约束没有被破坏
I 隔离性
该事务对与其他事务不可见 并发控制 可串行化 锁
D 持久性 durability
一旦事务提交,就是永久性的,即使发生宕机故障,数据库也能将数据恢复 持久性保证事务系统的高可靠性,而不是高可用性
## 7.1.2 分类
- 扁平事务
- 带有保存点的扁平事务
保存点用来通知系统应该记住事务当前的状态,一边当之后发生错误时,事务能回到保存点当时的状态
SAVE WORK
- 链事务
提交一个事务时不需要释放数据对象,将必要的处理上下文隐式的传递给下一个要开始的事务。将提交事务操作和开始下一个事务操作合并成为一个原子操作。
与带有保存点的扁平事务相比,带有保存点的扁平事务能回滚到任意正确的保存点。
链事务的回滚仅限于当前事务,即只能恢复到最近一个保存点。对于锁的处理也不相同。链事务在COMMIT后即释放了当前事务的所有锁。
带有保存点的扁平事务不影响迄今为止锁持有的锁
- 嵌套事务
- 分布式事务
7.2 事务的实现
事务的隔离性有锁来实现,原子性,一致性持久性通过数据库的redo log 和 undo log 完成
redo log 称为重做日志,用来保证事务的原子性和持久性
undo log 用来保证事务的一致性
redo 和undo 都可以视为一种恢复操作, redo 恢复提交事务修改的页操作, undo回滚行记录到某个特定的版本
7.2.1 redo
1、基本概念
重做日志用来实现事物的持久性。
由两部分组成
- 重做日志缓冲 redo log buffer
- 重做日志文件 redo log file
InnoDb时事务的存储引擎,通过Force Log at Commit机制实现事务的持久性。 即当事务提交时,必须先将事务的所有日志写入到重做日志文件进行持久化。待事务的COMMIT的操作完成才算完成
redo log基本上都是顺序写的,数据库运行不需要对redo log的文件进行读取操作。
undo log 要随时进行读写
为了确保每次日志都写入重做日志文件,在每次将重做日志缓冲写入重做日志文件后,InnoDB存储引擎都需要调用一次fsync操作。
O_Direct
https://blog.csdn.net/zdy0_20...
参数innodb_flush_log_at_trx_commit用来控制重做日志刷新到磁盘的策略
- 1 表示事务提交一次必须调用一次fsync
- 0 表示事务提交时不进行写入重做日志,尽在master中完成
- 2 表示事务提交时,将重做日志写入文件系统缓存,不进行fsync。
binlog 用来进行point in time 的恢复即主从复制环境的建立
重做日志时在innoDB存储引擎层产生的,而二进制日志是MySQL数据库的上层产生的。
二进制日志是一种逻辑日志,记录的是对应的SQL语句
InnoDB存储引擎层面的重做日志是物理格式日志,其记录的是对于每个页的修改
二进制日志只在事务提交完成后进行一次写入,而InnoDB存储引擎的重做日志在事务进行中不断地被写入,表现为日志不是随事务提交而顺序写入的。
log block
重做日志中 都是以512字节进行存储的。称为重做日志快
若一个页中产生的重做日志数量大于512字节,那么需要分割为多个重做日志块进行处理。
同时,由于重做日志块的大小和磁盘扇区大小一样,都是512字节。因此重做日志的写入可以保证原子性,不需要double write
log group
LSN
log sequence number 代表的是日志序列号
表示
- 重做日志写入的总量
- checkpoint的位置
- 页的版本
LSN 不仅记录在重做日志中,还存在于每个页中。 表示该页最后刷新时LSN的大小。
可以根据LSN判断是否需要进行恢复操作
恢复
7.2.1 undo
事务需要进行回滚操作,这是就需要undo
redo 存放存在重做日志文件中, undo村房子啊数据库内部的一个特殊的段中,这个段称为undo段
undo位于共享表空间内
undo是逻辑日志,因此只是将数据库逻辑地恢复到原来的样子。所有修改都被逻辑的取消了。但数据结构和页本身在回滚之后可能大不相同
除了回滚操作,undo的另一个作用是mvcc,即在InnoDB存储引擎中的MVCC的实现通过undo来完成的。
undo log 也会产生redo log 也就是undo log 的产生伴随redo log的产生,这是因为undo log也需要持久性的保护
当事务提交时,InnoDB存储引擎会做以下的事情
- 将undo log 放入列表中,以供之后的purge操作
- 判断undo log 所在的页是否可重用,若可以分配给下个事务使用
7.2.3 purge
delete 和 update 并不会直接删除原有的数据
真正删除行记录的操作被延时到purge操作
purge最终完成delete 和update操作,是因为 InnoDB存储引擎支持MVCC,所以记录不能再事务提交时立即进行处理。这时,其他事务可能正在引用这行。
7.3 事务控制语句
SET AUTOCOMMIT=0
BEGIN
START TRANSACTION
ROLLBACK
SAVEPOINT identifier
RELEASE SAVEPOINT identifier
ROLLBACK TO [SAVEPOINT] IDENTIFIER
SET TRANSACTION : 设置事务隔离级别
7.6 事务隔离级别
- READ UNCOMMITTED
- READ COMMITTED
- REPEATABLE READ
- SERIALIZABLE
7.7 分布式事务
分布式事务是指允许多个独立的事务资源参与到一个全局的事务中。
在使用分布式事务时,InnoDB存储引擎的事务隔离级别必须设置为SERIALIZABLE
XA
分布式事务由
- 一个或多个资源管理器
- 一个事务管理器
- 一个应用程序组成