MySQL三大日志是什么?#
说出 undolog、redolog、binlog 三种日志的作用。
回答#
- undo log是Innodb存储引擎层生成的日志,实现了事务中的原子性,主要用于事务回滚和MVCC。在事务没提交之前,Innodb会先记录更新前的数据记录 undo log中,回滚时利用 undo log 来进行回滚。
- redo log 也是Innodb存储引擎层的日志,属于物理日志,记录了某个数据页做了什么修改,实现了事务的持久性,主要用于掉电等故障恢复。比如某个事务提交了,脏页数据还没有刷盘,如果 MySQL 机器断电了,脏页的数据就丢失了,MySQL 重启后可以通过redolog日志,可以将已提交事务的数据恢复回来。
- binlog 是 Server 层生成的日志,主要用于数据备份和主从复制。在完成一条更新操作后,Server 层会生成一条 binlog,等之后事务提交的时候,会将该事务执行过程中产生的所有 binlog 统一写入 binlog 文件。binlog 文件是记录了所有数据库表结构变更和表数据修改的日志,不会记录查询类的操作。
redo log 和 binlog 的区别和应用场景?#
redo log 和 binlog 有4个区别的地方。
适用对象不同:
- binlog 是 MySQL 的 Server 层实现的日志,所有存储引擎都可以使用;
- redo log 是 Innodb 存储引擎实现的日志;
文件格式不同:
- binlog 有 3 种格式类型,分别是 STATEMENT(默认格式)、ROW、 MIXED,区别如下:
- STATEMENT:每一条修改数据的 SQL 都会被记录到 binlog 中(相当于记录了逻辑操作,所以针对这种格式, binlog 可以称为逻辑日志),主从复制中 slave 端再根据 SQL 语句重现。但 STATEMENT 有动态函数的问题,比如你用了 uuid 或者 now 这些函数,你在主库上执行的结果并不是你在从库执行的结果,这种随时在变的函数会导致复制的数据不一致;
- ROW:记录行数据最终被修改成什么样了(这种格式的日志,就不能称为逻辑日志了),不会出现 STATEMENT 下动态函数的问题。但 ROW 的缺点是每行数据的变化结果都会被记录,比如执行批量 update 语句,更新多少行数据就会产生多少条记录,使 binlog 文件过大,而在 STATEMENT 格式下只会记录一个 update 语句而已;
- MIXED:包含了 STATEMENT 和 ROW 模式,它会根据不同的情况自动使用 ROW 模式和 STATEMENT 模式;
- redo log 是物理日志,记录的是在某个数据页做了什么修改,比如对 XXX 表空间中的 YYY 数据页 ZZZ 偏移量的地方做了AAA 更新;
写入方式不同:
- binlog 是追加写,写满一个文件,就创建一个新的文件继续写,不会覆盖以前的日志,保存的是全量的日志。
- redo log 是循环写,日志空间大小是固定,全部写满就从头开始,保存未被刷入磁盘的脏页日志。
用途不同:
- binlog 用于备份恢复、主从复制;
- redo log 用于掉电等故障恢复。
面试的时候,重点说出两个日志的内容和应用场景的区别。
回答#
- redo log 是 InnoDB 引擎实现的日志,属于物理日志,记录了 Innodb 存储引擎对数据页所做的修改操作,主要用于崩溃恢复,比如某个事务提交了,脏页数据还没有刷盘,如果 MySQL 机器断电了,脏页的数据就丢失了,MySQL 重启后可以通过重做日志,可以将已提交事务的数据恢复回来。
- binlog 是 server 层实现的日志,保存了所有对数据库的增删改操作,binlog 有三种日志格式,日志的内容可能是 SQL 语句、数据本身或两者的混合,主要用于数据库备份和归档,也用于主从复制。
redo log 和 binlog 在恢复数据库有什么区别?#
考察 redo log 和 binlog 应用区别。
回答#
- binlog 是追加写,写满一个文件,就创建一个新的文件继续写,不会覆盖以前的日志,保存了所有对数据库的更新操作,可以用来恢复数据库某个时刻的数据或者全量恢复数据库数据。
- redo log 是循环写,日志空间大小是固定,全部写满就从头开始,保存的是 Innodb 存储引擎对数据页所做的修改操作,用来恢复因中途 MySQL 断电丢失的脏页数据。
为什么崩溃恢复不用binlog 而用redolog?#
回答#
binlog 是 server 层的日志,不会记录 innodb 存储引擎层中有哪些数据页没有被刷盘,redolog 是 innodb 层的日志,可以记录哪些脏页没有被刷盘,崩溃恢复的时候,恢复的粒度更细粒,可以精确到需要恢复的数据页,而 binlog 保存的是全量日志,没办法做到这一点,所以崩溃恢复用的是redolog
redo log 是怎么实现持久化的?#
- 先说明没有 redo log 前,数据库发生宕机时,脏页数据可能会发生丢失的问题。
- 再说明引入了 redo log 后,是怎么实现持久化的。
回答#
事务执行过程更新的数据,并不是在事务提交的时候,就把修改的数据刷入磁盘的,而是修改 buffer pool 中数据页,并标记为脏页,然后后台再找合适的时间刷盘。
如果事务提交了,脏页数据没有刷盘时,数据库发生宕机,这就会导致事务修改的数据丢失了。
所以 MySQL 就引入了 redo log, redo log 保存的内容是物理日志,主要是记录Innodb对某个数据页的修改操作,当事务提交的时候,redo log 会先刷入磁盘,因为 redo log 保存了数据页的修改操作,即使脏页数据没有刷盘时数据库发生宕机了,重启后 MySQL 通过重放 redo log ,就能恢复未刷盘的脏页,保证了数据的持久化。
redo log除了崩溃恢复还有什么其他作用?#
写入 redo log 的方式使用了追加操作, 所以磁盘操作是顺序写,而写入数据需要先找到写入位置,然后才写到磁盘,所以磁盘操作是随机写。
磁盘的「顺序写 」比「随机写」 高效的多,因此 redo log 写入磁盘的开销更小。针对「顺序写」为什么比「随机写」更快这个问题,可以比喻为你有一个本子,按照顺序一页一页写肯定比写一个字都要找到对应页写快得多。
可以说这是 WAL 技术的另外一个优点:MySQL 的写操作从磁盘的「随机写」变成了「顺序写」,提升语句的执行性能。这是因为 MySQL 的写操作并不是立刻更新到磁盘上,而是先记录在日志上,然后在合适的时间再更新到磁盘上。
针对为什么需要 redo log 这个问题我们有两个答案:
- 实现事务的持久性,让 MySQL 有 crash-safe 的能力,能够保证 MySQL 在任何时间段突然崩溃,重启后之前已提交的记录都不会丢失;
- 将写操作从「随机写」变成了「顺序写」,提升 MySQL 写入磁盘的性能。
回答#
写 Redolog 日志是追加的形式,所以 redolog 写磁盘是一个顺序写的过程,而数据页写磁盘是一个随机写的过程,顺序写的性能是比随机写性能高的,事务在提交的时候,是先写日志再写数据的机制,相当于把 MySQL 写入磁盘的操作从磁盘随机写成了顺序写,所以 redo log 还可以起到提升 MySQL 写入磁盘性能的作用。
为什么需要两阶段提交?#
回答#
两阶段提交是为了保证 redo log 和 binlog 逻辑一致,从而保证主从复制的时候不会出现数据不一致的问题。
事务提交后,redo log 和 binlog 都要持久化到磁盘,但是这两个是独立的逻辑,可能出现半成功的状态,比如在主从复制的场景下,如果在将 redo log 刷入到磁盘之后, MySQL 突然宕机了,而 binlog 还没有来得及写入磁盘,这时候主库是最新的数据,而从库是旧数据,这样就造成两份日志之间的逻辑不一致。
两阶段提交的过程?#

回答#
两阶段提交把事务的提交拆分成了 2 个阶段,分别是准备阶段和提交阶段。
- 准备阶段会将 redo log 状态设置为 prepare 状态,然后将 redo log 刷入磁盘;
- 提交阶段会将 binlog 刷入磁盘,然后设置 redo log 设置为 commit 状态,到这里两阶段就已经完成了。
在两阶段提交中,是以 binlog 刷入磁盘时机作为事务提交成功的标志的:
- 如果 binlog 还没刷入磁盘的时候,MySQL 就发生了崩溃,MySQL 重启的时候就需要回滚事务;
- 如果 binlog 刷入磁盘,即使 redo log 没有设置 commit 状态,MySQL 就发生了崩溃,MySQL 重启的时候就会提交事务。

