Log Buffer:
log buffer到redo log有3种方式。FS page buffer是文件系统页缓冲。
方式一:每隔1秒,log buffer到FS page buffer,FS page buffer到redo log。效率高。
方式二:每次事务提交,log buffer到FS page buffer,FS page buffer到redo log。默认方式,可靠性强。
方式三:每次事务提交,log buffer到FS page buffer;每隔1秒,FS page buffer到redo log。折中方式,推荐。
参考:MySQL各种“Buffer”之Log Buffer - 墨天轮
二进制日志
Mysql的binlog是二进制日志文件。包括日志索引文件(后缀为.index)和日志文件(后缀为.00000*)。日志索引文件记录日志文件。日志文件记录数据定义和写方式的数据操作语句。(数据定义、数据操作:参考:https://blog.csdn.net/haoranhaoshi/article/details/109804069)
参考:
MySQL的Binlog原理_击水三千里的博客-CSDN博客_数据库binlog
MySQL Binlog 介绍 - whirlys - 博客园
事务日志
innodb事务日志包括undo log和redo log。
https://blog.csdn.net/bjmsb/article/details/108467720
undo log:
事务操作前会将数据操作语句记录到undo 备份到undo log中,可以供快照读。如果需回滚,就将数据拷贝回缓存里。undo log为了事务原子性。
数据库事务四大特性中有一个是原子性,具体来说就是 原子性是指对数据库的一系列操作,要么全部成功,要么全部失败,不可能出现部分成功的情况。实际上,原子性底层就是通过undo log
实现的。undo log
主要记录了数据的逻辑变化,比如一条INSERT
语句,对应一条DELETE
的undo log
,对于每个UPDATE
语句,对应一条相反的UPDATE
的undo log
,这样在发生错误时,就能回滚到事务之前的数据状态。同时,undo log
也是MVCC
(多版本并发控制)实现的关键。
根据undo buffer中的操作可以回滚。回滚过程中故障,重启数据库时执行undo log中的操作回滚。
redo log:
redo log
包括两部分:一个是内存中的日志缓冲(redo log buffer,也有资料是redo buffer
),另一个是磁盘上的日志文件(redo log file
)。mysql
每执行一条DML
语句,先将记录写入redo log buffer
,后续某个时间点再一次性将多个操作记录写到redo log file
。这种先写日志,再写磁盘的技术就是MySQL
里经常说到的WAL(Write-Ahead Logging)
技术。
如果提交过程中,发生故障。重启数据库时,会执行redo log中的操作。redo log为了事务持久性。
- SHOW VARIABLES LIKE 'innodb_log_files_in_group';
查看配有多少个redo log文件。
- SHOW VARIABLES LIKE 'innodb_log_file_size';
查看每个redo log文件的大小。
- SHOW VARIABLES LIKE 'innodb_log_group_home_dir';
查看redo log文件的目录。
- redo log文件命名:ib_logfile数字编号。如:ib_logfile0,ib_logfile1,...
- 多个redo log文件,在逻辑上看成是一个完整的,循环使用的文件。
- 每个redo log文件,都分成一个个512字节的小块block。每个redo log文件的前4个block作为管理块,不会用于存储redo log记录。
- 从逻辑上看,redo log文件是一个循环块数组,每个块512字节。
二进制日志和redo log
redo log不是二进制日志。虽然二进制日志中也记录了innodb表的很多操作,也能实现重做的功能,但是它们之间有很大区别。
- 二进制日志是在存储引擎的上层产生的,不管是什么存储引擎,对数据库进行了修改都会产生二进制日志。而redo log是innodb层产生的,只记录该存储引擎中表的修改。并且二进制日志先于redo log被记录。具体的见后文group commit小结。
- 二进制日志记录操作的方法是逻辑性的语句。即便它是基于行格式的记录方式,其本质也还是逻辑的SQL设置,如该行记录的每列的值是多少。而redo log是在物理格式上的日志,它记录的是数据库中每个页的修改。
- 二进制日志只在每次事务提交的时候一次性写入缓存中的日志"文件"(对于非事务表的操作,则是每次执行语句成功后就直接写入)。而redo log在数据准备修改前写入缓存中的redo log中,然后才对缓存中的数据执行修改操作;而且保证在发出事务提交指令时,先向缓存中的redo log写入日志,写入完成后才执行提交动作。
- 因为二进制日志只在提交的时候一次性写入,所以二进制日志中的记录方式和提交顺序有关,且一次提交对应一次记录。而redo log中是记录的物理页的修改,redo log文件中同一个事务可能多次记录,最后一个提交的事务记录会覆盖所有未提交的事务记录。例如事务T1,可能在redo log中记录了 T1-1,T1-2,T1-3,T1* 共4个操作,其中 T1* 表示最后提交时的日志记录,所以对应的数据页最终状态是 T1* 对应的操作结果。而且redo log是并发写入的,不同事务之间的不同版本的记录会穿插写入到redo log文件中,例如可能redo log的记录方式如下: T1-1,T1-2,T2-1,T2-2,T2*,T1-3,T1* 。
- 事务日志记录的是物理页的情况,它具有幂等性,因此记录日志的方式极其简练。幂等性的意思是多次操作前后状态是一样的,例如新插入一行后又删除该行,前后状态没有变化。而二进制日志记录的是所有影响数据的操作,记录的内容较多。例如插入一行记录一次,删除该行又记录一次。
redo log与binlog区别
redo log | binlog | |
---|---|---|
文件大小 | redo log 的大小是固定的。 | binlog 可通过配置参数max_binlog_size 设置每个binlog 文件的大小。 |
实现方式 | redo log 是InnoDB 引擎层实现的,并不是所有引擎都有。 | binlog 是Server 层实现的,所有引擎都可以使用 binlog 日志 |
记录方式 | redo log 采用循环写的方式记录,当写到结尾时,会回到开头循环写日志。 | binlog 通过追加的方式记录,当文件大小大于给定值后,后续的日志会记录到新的文件上 |
适用场景 | redo log 适用于崩溃恢复(crash-safe) | binlog 适用于主从复制和数据恢复 |
快照读、当前读
快照读(也称普通读):SQL读取的数据是快照版本,也就是历史版本,普通的SELECT就是快照读 innodb快照读,数据的读取将由 cache(原本数据) + undo(事务修改过的数据) 两部分组成。SELECT不加锁。
当前读(也称锁定读):SQL读取的数据是最新版本。通过锁机制来保证读取的数据无法通过其他事务进行修改 UPDATE、DELETE、INSERT、SELECT … LOCK IN SHARE MODE、SELECT … FOR UPDATE都是 当前读。
对于 SERIALIZABLE 隔离级别来说,如果 autocommit 系统变量被设置为OFF,那普通读的语句会转变为锁定读,和在普通的 SELECT 语句后边加 LOCK IN SHARE MODE 达成的效果一样。
共享锁、排他锁
SELECT … LOCK IN SHARE MODE加共享锁(S锁, share lock)。加了共享锁,其他事务可以再加共享锁,不能加排他锁。其他事务可以读取数据,但不能修改该数据。UPDATE、DELETE、INSERT、SELECT … FOR UPDATE加排他锁(X锁, exclusive lock)。加了排他锁,其他事务不能加锁。其他事务可以读取数据,但不能修改该数据。
关于undo log的补充:
2. 行的更新过程
下面演示下事务对某行记录的更新过程:
1. 初始数据行
F1~F6是某行列的名字,1~6是其对应的数据。后面三个隐含字段分别对应该行的事务号和回滚指针,假如这条数据是刚INSERT的,可以认为ID为1,其他两个字段为空。
2.事务1更改该行的各字段的值
当事务1更改该行的值时,会进行如下操作:
- 用排他锁锁定该行
- 记录redo log
- 把该行修改前的值Copy到undo log,即上图中下面的行
- 修改当前行的值,填写事务编号,使回滚指针指向undo log中的修改前的行
3.事务2修改该行的值
与事务1相同,此时undo log,中有有两行记录,并且通过回滚指针连在一起。
因此,如果undo log一直不删除,则会通过当前记录的回滚指针回溯到该行创建时的初始内容,所幸的时在Innodb中存在purge线程,它会查询那些比现在最老的活动事务还早的undo log,并删除它们,从而保证undo log文件不至于无限增长。