@ -1852,21 +1852,182 @@ Mysql中若是为了保证数据的持久性, 在每提交一个事务就将日
`InnoDB` 支持`3`种常见索引:
- 哈希索引
- `B+ ` 树索引
- 全文索引
- 哈希索引
### 哈希 索引
### B+树 索引
**B+树是为磁盘或其它直接存取辅助设备涉及的一种近似平衡的查找树**。在InnoDB存储引擎中, B+树索引**根据键值类型**可以分为**聚集索引**和**非聚集索引**。
#### 聚集索引(主键索引)
### B+树索引
**聚集索引(Clustered index)**的**非叶子节点**存放**索引页**, **叶子节点**存放**数据页**,数据页中的所有的行记录都是按照键值递增方式顺序的存放在同一层的叶子结点上,各叶子结点通过前驱后继两个指针串联成一个双向循环链表(数据页本身就是聚集索引的一部分)。
![Innodb-聚集索引 ](images/Database/Innodb-聚集索引.png )
InnoDB存储引擎在创建表的过程中就会根据主键自动构造一棵B+树索引, 其高度一般是2~4层, 故需要2~4次的查询才能找到对应的数据页。聚集索引使用时, 根据主键在B+树中依次比较,直到找到底层对应的数据页(叶子节点),然后通过**二分查找**的方式在数据页中**定位到目标行**,故其对针对主键的排序查找和范围查找的速度是特别快的。
### 全文索引
#### 非聚集索引(辅助索引)
**非聚集索引**的**非叶子节点**包含对应的**辅助索引键值**, 叶子节点不同于聚集索引, 不含行数据, 而是包含了一个聚集索引键( 主键) , 通过查找非聚集索引B+树找到其叶子节点上的主键, 然后再去聚集索引B+树上去查找对应的行数据。其树高一般也是2~4层, 故查询次数较聚集索引多了一倍。
![Innodb-非聚集索引 ](images/Database/Innodb-非聚集索引.png )
### 全文索引(FULLTEXT)
B+树索引的特点是可以通过索引字段等值查询( where a = “xxx”) 或者进行前缀匹配( where a like “xxx%”) 查找, 然而如果数据库中存储的数据为blog或weibo之类的长篇文本, 用户一般希望以模糊匹配( where a like “%xxx%”) 的方式来查询, 由于条件的前缀并不是固定的值, 所以没法利用B+树索引进行比较查找,故而效率会很低,为了解决这类问题,引入了全文索引。
全文索引( Full-Text Search) 是将数据库中某段文字( 或词语) 快速查找出来的技术。其本质是一种映射表结构, 在表中存储了单词与单词所在文档的位置的映射关系( 其key是对应的数据( 单词) , value是数据的位置) , 相对于B+树索引的key-val来讲, 顺序是倒过来的, 所以也叫倒排索引。这个索引表, 也叫做辅助表。
![Innodb-全文索引 ](images/Database/Innodb-全文索引.png )
InnoDB存储引擎生成了6张辅助表以提高全文检索的并发性能, 同时该表是持久化的保存在磁盘上的, 在服务起来后, 动态将其加载到内存里。辅助表在内存中并不是表结构( 能想来表的查询效率并不高) , 其在内存中的格式是一棵红黑树, 根据( text,documents) 来进行排序, 该缓存也被起个响亮的名字——全文检索索引缓存。
参数innodb_ft_cache_size用来控制全文索引缓存的大小, 默认一般是32M。缓存满时, 会将其中的( text,documents) 映射信息保存到磁盘中去。若缓存设置过小, 可能会导致频繁换页引起索引效率下降。
另外值得一提的是, InnoDB存储引擎的全文索引只支持如英文这类的有单词分界符的语言, 像中文这样的语言是不支持的
### 自适应哈希索引
B+树索引树高一般是2~4层, 故需要2~4次的查询才能找到对应的数据页, 而哈希索引是一种非常快的查找方法, 通常情况下它的时间复杂度是O(1)的。InnDB存储引擎一般会默认开启自适应哈希索引的开关, 通过如下命令可以查看:
```sql
show variables like '%adaptive_hash%';
```
开启后, 引擎会自动监控对表上各个索引页的查询, 如果观察到建立哈希索引可以带来一定的效率提升, 则会自动构建哈希索引, 所以称之为自适应哈希索引( Adaptive Hash Index) 。AHI是通过缓冲池中的B+树索引页构造而来, 无需访问磁盘, 故而创建速度是很快的。同样的, 因为是自适应的, 所以无法主动的去构造AHI, 我们只能控制它的开启或关闭:
```sql
set global innodb_adaptive_hash_index=off/on
```
该引擎根据访问的频率以及查询条件来为某些热点页建立AHI:
- 查询条件必须是指定的值而不是范围: 如where a=xxx and b=xxx
- 以该模式的查询条件连续访问100次以上( 或查询次数达到了页中记录的1/16)
![自适应哈希索引 ](images/Database/自适应哈希索引.png )
InnoDB存储引擎官方提供的性能数据显示, 开启AHI后, 读取和写入性能可以提高2倍, 辅助索引的连接操作性能可以提高5倍, 显然, 一般情况下开启AHI还是很有必要且值得的。另外, 我们还可以通过命令来查看当前AHI的使用情况:
```sql
mysql> show engine innodb status \G
-------------------------------------
INSERT BUFFER AND ADAPTIVE HASH INDEX
-------------------------------------
Ibuf: size 1, free list len 0, seg size 2, 0 merges
merged operations:
insert 0, delete mark 0, delete 0
discarded operations:
insert 0, delete mark 0, delete 0
Hash table size 553229, node heap has 17 buffer(s)
0.00 hash searches/s, 0.00 non-hash searches/s
```
其中包括AHI的大小、使用情况、每秒使用AHI搜索的情况。通过hash searches/non-hash searches可以大概的了解AHI的调用频率。根据频率的大小, 我们可以考虑是否需要调整它的开关状态。
# MySQL日志
**重做日志( redo log) 、二进制日志( bin log) 、回滚日志( undo log) 、错误日志( error log) 、慢查询日志( slow query log) 、一般查询日志( general log) 、中继日志( relay log) 。**
## 二进制日志(bin log)
`binlog` 用于记录数据库执行的写入性操作(不包括查询)信息,以二进制的形式保存在磁盘中。`binlog` 是 `mysql` 的逻辑日志(即SQL语句),并且由 `Server` 层进行记录,使用任何存储引擎的 `mysql` 数据库都会记录 `binlog` 日志。`binlog` 是通过追加的方式进行写入的,可以通过`max_binlog_size` 参数设置每个 `binlog` 文件的大小,当文件大小达到给定值之后,会生成新的文件来保存日志。
**作用**
- ** 主从复制**: 在主从复制中, 从库利用主库上的binlog进行重播, 实现主从同步
- ** 数据恢复**: 通过使用mysqlbinlog`工具来实现数据库基于时间点的还原
### 刷盘时机
对于 `InnoDB` 存储引擎而言,只有在事务提交时才会记录`biglog` ,此时记录还在内存中,那么 `biglog` 是什么时候刷到磁盘中的呢?`mysql` 通过 `sync_binlog` 参数控制 `biglog` 的刷盘时机,取值范围是 `0-N` :
- `sync_binlog=0` :不去强制要求,由系统自行判断何时写入磁盘
- `sync_binlog=1` :每次 `commit` 的时候都要将 `binlog` 写入磁盘
- `sync_binlog=N(N>1)` : 每N个事务, 才会将 `binlog` 写入磁盘
从上面可以看出, `sync_binlog` 最安全的是设置是 `1` ,这也是`MySQL 5.7.7`之后版本的默认值。但是设置一个大一些的值可以提升数据库性能,因此实际情况下也可以将值适当调大,牺牲一定的一致性来获取更好的性能。
### 日志格式
`binlog` 日志有三种格式,日志格式通过 `binlog-format` 指定。在 `MySQL 5.7.7` 之前,默认的格式是 `STATEMENT` , `MySQL 5.7.7` 之后,默认值是 `ROW` 。
- `STATMENT` :基于`SQL`语句复制(`statement-based replication, SBR`), 每一条会修改数据的sql语句会记录到`binlog`中
- ** 优点**: 不需要记录每一行的变化, 减少了binlog日志量, 节约了IO, 从而提高了性能
- ** 缺点**: 在某些情况下会导致主从数据不一致, 比如执行sysdate()、slepp() 等
- `ROW` :基于行复制(`row-based replication, RBR` ), 不记录每条sql语句的上下文信息, 仅需记录哪条数据被修改了。
- ** 优点**: 不会出现某些特定情况下的存储过程、或function、或trigger的调用和触发无法被正确复制的问题
- ** 缺点**:会产生大量的日志,尤其是` alter table ` 的时候会让日志暴涨
- `MIXED` :基于`STATMENT` 和 `ROW` 两种模式的混合复制(`mixed-based replication, MBR` ),一般的复制使用`STATEMENT` 模式保存 `binlog` ,对于 `STATEMENT` 模式无法复制的操作使用 `ROW` 模式保存 `binlog`
## 重做日志(redo log)
**重做日志是InnoDB引擎层日志, 用来记录事务操作引起数据变化, 记录的是数据页的物理修改。**包括两部分:
- ** 内存中的日志缓冲(redo log buffer)**
- ** 磁盘上的日志文件(redo logfile)**
MySQL 每执行一条 DML 语句,先将记录写入 redo log buffer, 后续某个时间点再一次性将多个操作记录写到 redo log file, 种先写日志再写磁盘的技术就是 WAL(Write-Ahead Logging) 技术。之后MySQL会在合适的时候将操作记录 flush 到磁盘上面, flush 的条件可能是系统比较空闲,或 redo log 空间不足时。redo log 文件的大小是固定的, 如可以是由4个1GB文件组成的集合。
**WAL(Write-Ahead Logging)**
WAL( Write-Ahead Logging, 预写式日志) 是一种数据安全写入机制, 即**先写日志,再写磁盘**,这样保证数据的安全性。先在内存中提交事务,然后写日志(在InnoDB中就是Redo Log, 日志是为了防止宕机导致内存数据丢失),然后再后台任务中把内存中的数据异步刷到磁盘。
**作用**
- ** 确保事务的持久性**
- ** 防止发生故障时,尚有脏页未写入磁盘**。在重启mysql服务时, 根据redo log进行重做, 从而达到事务的持久性特性
### 写入流程
为了控制 `redo log` 的写入策略,`innodb_flush_log_at_trx_commit` 会有下面 3 中取值:
- `0` : **每次提交事务只写在 `redo log buffer` 中**
- `1` : **每次提交事务持久化到磁盘**
- `2` : **每次提交事务写到 文件系统的 `page cache` 中**
### 刷盘场景
redo log 实际的触发 fsync 操作写盘包含以下几个场景:
- ** 后台每隔 1 秒钟的线程轮询**
- **innodb_flush_log_at_trx_commit 设置成 1 时,事务提交时触发**
- **innodb_log_buffer_size 是设置 redo log 大小的参数** 。当 redo log buffer 达到 innodb_log_buffer_size / 2 时,也会触发一次 fsync
## 回滚日志(undo log)
回滚日志( undo log) 主要存储的是数据的逻辑变化日志, 用于回滚操作。比如我们要 insert 一条数据,那么 undo log 就会生成一条对应的 delete 日志。所以当需要回滚时, 只需要利用undo log 就可以恢复都修改前的数据。
**作用**
- ** 提供回滚操作**。undo log实现事务的原子性, 保存了事务发生之前的数据的一个版本, 可以用于回滚
- ** 提供多版本并发控制( MVCC) 下的读**。也即非锁定读
@ -1895,20 +2056,13 @@ Mysql中若是为了保证数据的持久性, 在每提交一个事务就将日
### Hash索引
![Hash索引 ](images/Database/Hash索引.png )
**原理**
- 事先将索引通过 hash算法后得到的hash值(即磁盘文件指针) 存到hash表中
- 在进行查询时, 将索引通过hash算法, 得到hash值, 与hash表中的hash值比对。通过磁盘文件指针, 只要**一次磁盘IO**就能找到要的值
例如: 在第一个表中, 要查找col=6的值。hash(6) 得到值, 比对hash表, 就能得到89。性能非常高。
**原理**是先将索引通过hash算法后得到的hash值(即磁盘文件指针) 存到hash表中。在进行查询时, 将索引通过hash算法, 得到hash值, 与hash表中的hash值比对。通过磁盘文件指针, 只要**一次磁盘IO**就能找到要的值。
![Hash索引 ](images/Database/Hash索引.png )
**优点**
- 快速查询: 参与索引的字段只要进行Hash运算之后就可以快速定位到该记录, 时间复杂度约为1
- ** 快速查询**。参与索引的字段只要进行Hash运算之后就可以快速定位到该记录, 时间复杂度约为1
**缺点**
@ -1920,20 +2074,19 @@ Mysql中若是为了保证数据的持久性, 在每提交一个事务就将日
### R-Tree索引
空间数据索引。
### B-Tree索引
**背景**: 二叉查找树查询的时间复杂度是O(logN), 查找速度最快和比较次数较少。但用于数据库索引, 当数据量过大, 不可能将所有索引加载进内存, 使用二叉树会导致磁盘IO过于频繁, 最坏的情况下磁盘IO的次数由树的高度来决定。
**背景**: 二叉查找树查询的时间复杂度是O(logN), 查找速度最快和比较次数较少。但用于数据库索引, 当数据量过大, 不可能将所有索引加载进内存, 使用二叉树会导致磁盘I/O过于频繁, 最坏的情况下磁盘I/O的次数由树的高度来决定。
B-Tree(平衡多路查找树)对二叉树进行了横向扩展,能很好解决红黑树中遗留的高度问题,使树结构更加**矮胖**, 使得一次IO能加载更多关键字, 对比在内存中完成, 减少了磁盘IO次数, 更适用于大型数据库, 但是为了保持自平衡, 插入或者删除元素都会导致节点发生裂变反应, 有时候会非常麻烦。
B-Tree(平衡多路查找树)对二叉树进行了横向扩展,能很好解决红黑树中遗留的高度问题,使树结构更加**矮胖**, 使得一次I/O能加载更多关键字, 对比在内存中完成, 减少了磁盘I/O次数, 更适用于大型数据库, 但是为了保持自平衡, 插入或者删除元素都会导致节点发生裂变反应, 有时候会非常麻烦。
![索引-B树结构 ](images/Database/索引-B树结构.png )
**存在问题**
- ** 不支持范围查询的快速查找**。可以用B+Tree解决
- ** 每行数据量很大时, 会导致B-Tree深度较大, 进而影响查询效率**。可以用B+Tree解决
**案例分析**: 模拟下查找key为10的data的过程
@ -1949,24 +2102,30 @@ B-Tree(平衡多路查找树)对二叉树进行了横向扩展,能很好解决
**存在问题**
### B+Tree索引
- ** 不支持范围查询的快速查找**。可以用B+Tree解决
B+树是B-树的变体, 也是一种多路搜索树。其定义基本与B-树相同, 与B-Tree相比B+Tree有以下不同点:
- ** 每行数据量很大时, 会导致B-Tree深度较大, 进而影响查询效率**。可以用B+Tree解决
- ** 非叶子结点的子树指针与关键字个数相同**
- ** 非叶子结点的子树指针P[i],指向关键字值属于[K[i], K[i+1])的子树( B-树是开区间)**
- ** 为所有叶子结点增加一个链指针**
- ** 所有关键字都在叶子结点出现**
- ** 内节点不存储data, 只存储key**
![索引-B+Tree结构 ](images/Database/索引-B+Tree结构.png )
**优点**
### B+Tree索引
- 单次请求涉及的磁盘IO次数少( 出度d大, 且非叶子节点不包含表数据, 树的高度小)
- 查询效率稳定(任何关键字的查询必须走从根结点到叶子结点,查询路径长度相同)
- 遍历效率高(从符合条件的某个叶子节点开始遍历即可)
B+树是B-树的变体, 也是一种多路搜索树。其定义基本与B-树相同,除了:
**缺点**
- 非叶子结点的子树指针与关键字个数相同
- 非叶子结点的子树指针P[i],指向关键字值属于[K[i], K[i+1])的子树( B-树是开区间)
- 为所有叶子结点增加一个链指针
- 所有关键字都在叶子结点出现
B+树最大的性能问题在于会产生大量的随机IO, 主要存在以下两种情况:
![索引-B+Tree结构 ](images/Database/索引-B+Tree结构.png )
- 主键不是有序递增的,导致每次插入数据产生大量的数据迁移和空间碎片
- 即使主键是有序递增的,大量写请求的分布仍是随机的
@ -1994,44 +2153,39 @@ B+树是B-树的变体, 也是一种多路搜索树。其定义基本与B-树
**优点**
- 单次请求涉及的磁盘IO次数少( 出度d大, 且非叶子节点不包含表数据, 树的高度小)
- 查询效率稳定(任何关键字的查询必须走从根结点到叶子结点,查询路径长度相同)
- 遍历效率高(从符合条件的某个叶子节点开始遍历即可)
**缺点**
B+树最大的性能问题在于会产生大量的随机IO, 主要存在以下两种情况:
- 主键不是有序递增的,导致每次插入数据产生大量的数据迁移和空间碎片
- 即使主键是有序递增的,大量写请求的分布仍是随机的
### B*Tree
是B+树的变体, 在B+树的非根和非叶子结点再增加指向兄弟的指针;
是B+树的变体,**在B+树的非根和非叶子结点再增加指向兄弟的指针**。
![索引机制-B星树 ](images/Database/索引机制-B星树.jpg )
B*树定义了非叶子结点关键字个数至少为(2/3)M, 即块的最低使用率为2/3( 代替B+树的1/2) 。
**B+树的分裂**
当一个结点满时, 分配一个新的结点, 并将原结点中1/2的数据复制到新结点, 最后在父结点中增加新结点的指针; B+树的分裂只影响原结点和父结点,而不会影响兄弟结点,所以它不需要指向兄弟的指针。
**B*树的分裂**
当一个结点满时, 如果它的下一个兄弟结点未满, 那么将一部分数据移到兄弟结点中, 再在原结点插入关键字, 最后修改父结点中兄弟结点的关键字( 因为兄弟结点的关键字范围改变了) ; 如果兄弟也满了, 则在原结点与兄弟结点之间增加新结点, 并各复制1/3的数据到新结点, 最后在父结点增加新结点的指针; 所以, B*树分配新结点的概率比B+树要低,空间使用率更高。
### R-Tree索引
空间数据索引( R-Tree) , MyISAM支持空间索引, 可以用作地理数据存储。
## 索引类型
### 普通索引
**单列索引是最基本的索引,它没有任何限制,允许在定义索引的列中插入重复值和空值。**
基本的索引类型,值可以为空,没有唯一性的限制。
```sql
-- 直接创建索引
@ -2059,7 +2213,7 @@ alter table `表名` drop index 索引名;
### 唯一索引
** 索引列中的值必须是唯一的,但是允许为空值(只允许存在一条空值)。**
索引列中的值必须是唯一的,但是允许为空值(只允许存在一条空值)。
```mysql
-- 创建单个索引
@ -2078,7 +2232,7 @@ ALTER TABLE table_name ADD UNIQUE index index_name(col_name,...);
### 主键索引
**索引列中的值必须是唯一的,不允许有空值。**
主键是一种唯一性索引,但它必须指定为`PRIMARY KEY`,每个表只能有一个主键。
```sql
-- 主键索引(创建表时添加)
@ -2117,7 +2271,7 @@ alter table table_name add index index_name(col_name,col_name2,...);
### 全文索引
**只能在文本类型 `CHAR` 、`VARCHAR`、`TEXT` 类型字段上创建全文索引**。字段长度比较大时, 如果创建普通索引, 在进行like模糊查询时效率比较低, 这时可以创建全文索引。 MyISAM和InnoDB中都可以使用全文索引。
全文索引的索引类型为`FULLTEXT`。全文索引可以在`varchar、char、text`类型的列上创建。可以通过`ALTER TABLE`或`CREATE INDEX`命令创建。对于大规模的数据集,通过`ALTER TABLE`(或`CREATE INDEX`)命令创建全文索引要比把记录插入带有全文索引的空表更快。`MyISAM`支持全文索引,`InnoDB`在mysql5.6之后支持了`全文索引`。 全文索引`不支持中文`需要借`sphinx(coreseek)`或`迅搜< 、code>技术处理中文。`
```mysql
-- 创建表的适合添加全文索引
@ -2399,106 +2553,6 @@ select * from t where k1=1 and k3=3;
# MySQL日志
**重做日志( redo log) 、二进制日志( bin log) 、回滚日志( undo log) 、错误日志( error log) 、慢查询日志( slow query log) 、一般查询日志( general log) 、中继日志( relay log) 。**
## 二进制日志(bin log)
`binlog` 用于记录数据库执行的写入性操作(不包括查询)信息,以二进制的形式保存在磁盘中。`binlog` 是 `mysql` 的逻辑日志(即SQL语句),并且由 `Server` 层进行记录,使用任何存储引擎的 `mysql` 数据库都会记录 `binlog` 日志。`binlog` 是通过追加的方式进行写入的,可以通过`max_binlog_size` 参数设置每个 `binlog` 文件的大小,当文件大小达到给定值之后,会生成新的文件来保存日志。
**作用**
- ** 主从复制**: 在主从复制中, 从库利用主库上的binlog进行重播, 实现主从同步
- ** 数据恢复**: 通过使用mysqlbinlog`工具来实现数据库基于时间点的还原
### 刷盘时机
对于 `InnoDB` 存储引擎而言,只有在事务提交时才会记录`biglog` ,此时记录还在内存中,那么 `biglog` 是什么时候刷到磁盘中的呢?`mysql` 通过 `sync_binlog` 参数控制 `biglog` 的刷盘时机,取值范围是 `0-N` :
- `sync_binlog=0` :不去强制要求,由系统自行判断何时写入磁盘
- `sync_binlog=1` :每次 `commit` 的时候都要将 `binlog` 写入磁盘
- `sync_binlog=N(N>1)` : 每N个事务, 才会将 `binlog` 写入磁盘
从上面可以看出, `sync_binlog` 最安全的是设置是 `1` ,这也是`MySQL 5.7.7`之后版本的默认值。但是设置一个大一些的值可以提升数据库性能,因此实际情况下也可以将值适当调大,牺牲一定的一致性来获取更好的性能。
### 日志格式
`binlog` 日志有三种格式,日志格式通过 `binlog-format` 指定。在 `MySQL 5.7.7` 之前,默认的格式是 `STATEMENT` , `MySQL 5.7.7` 之后,默认值是 `ROW` 。
- `STATMENT` :基于`SQL`语句复制(`statement-based replication, SBR`), 每一条会修改数据的sql语句会记录到`binlog`中
- ** 优点**: 不需要记录每一行的变化, 减少了binlog日志量, 节约了IO, 从而提高了性能
- ** 缺点**: 在某些情况下会导致主从数据不一致, 比如执行sysdate()、slepp() 等
- `ROW` :基于行复制(`row-based replication, RBR` ), 不记录每条sql语句的上下文信息, 仅需记录哪条数据被修改了。
- ** 优点**: 不会出现某些特定情况下的存储过程、或function、或trigger的调用和触发无法被正确复制的问题
- ** 缺点**:会产生大量的日志,尤其是` alter table ` 的时候会让日志暴涨
- `MIXED` :基于`STATMENT` 和 `ROW` 两种模式的混合复制(`mixed-based replication, MBR` ),一般的复制使用`STATEMENT` 模式保存 `binlog` ,对于 `STATEMENT` 模式无法复制的操作使用 `ROW` 模式保存 `binlog`
## 重做日志(redo log)
**重做日志是InnoDB引擎层日志, 用来记录事务操作引起数据变化, 记录的是数据页的物理修改。**包括两部分:
- ** 内存中的日志缓冲(redo log buffer)**
- ** 磁盘上的日志文件(redo logfile)**
MySQL 每执行一条 DML 语句,先将记录写入 redo log buffer, 后续某个时间点再一次性将多个操作记录写到 redo log file, 种先写日志再写磁盘的技术就是 WAL(Write-Ahead Logging) 技术。之后MySQL会在合适的时候将操作记录 flush 到磁盘上面, flush 的条件可能是系统比较空闲,或 redo log 空间不足时。redo log 文件的大小是固定的, 如可以是由4个1GB文件组成的集合。
**WAL(Write-Ahead Logging)**
WAL( Write-Ahead Logging, 预写式日志) 是一种数据安全写入机制, 即**先写日志,再写磁盘**,这样保证数据的安全性。先在内存中提交事务,然后写日志(在InnoDB中就是Redo Log, 日志是为了防止宕机导致内存数据丢失),然后再后台任务中把内存中的数据异步刷到磁盘。
**作用**
- ** 确保事务的持久性**
- ** 防止发生故障时,尚有脏页未写入磁盘**。在重启mysql服务时, 根据redo log进行重做, 从而达到事务的持久性特性
### 写入流程
为了控制 `redo log` 的写入策略,`innodb_flush_log_at_trx_commit` 会有下面 3 中取值:
- `0` : **每次提交事务只写在 `redo log buffer` 中**
- `1` : **每次提交事务持久化到磁盘**
- `2` : **每次提交事务写到 文件系统的 `page cache` 中**
### 刷盘场景
redo log 实际的触发 fsync 操作写盘包含以下几个场景:
- ** 后台每隔 1 秒钟的线程轮询**
- **innodb_flush_log_at_trx_commit 设置成 1 时,事务提交时触发**
- **innodb_log_buffer_size 是设置 redo log 大小的参数** 。当 redo log buffer 达到 innodb_log_buffer_size / 2 时,也会触发一次 fsync
## 回滚日志(undo log)
回滚日志( undo log) 主要存储的是数据的逻辑变化日志, 用于回滚操作。比如我们要 insert 一条数据,那么 undo log 就会生成一条对应的 delete 日志。所以当需要回滚时, 只需要利用undo log 就可以恢复都修改前的数据。
**作用**
- 保证数据的原子性。保存了事务发生之前的数据的一个版本,可以用于回滚
- 可以提供多版本并发控制下的读( MVCC) , 也即非锁定读
# 数据切分
## 水平切分