主题
《面渣逆袭》MySQL 篇 · 第 4/10 章。原版 PDF(下载 / 打印)
19.MySQL 日志文件有哪些?分别介绍下作用?

MySQL 日志文件有很多,包括:
错误日志(errorlog):错误日志文件对 MySQL 的启动、运行、关闭过程进行了记录,能帮助定位 MySQL 问题。
慢查询日志(slowquerylog):慢查询日志是用来记录执行时间超过 long_query_time 这个变量定义的时长的查询语句。通过慢查询日志,可以查找出哪些查询语句的执行效率很低,以便进行优化。
一般查询日志(generallog):一般查询日志记录了所有对 MySQL 数据库请求的信息,无论请求是否正确执行。
二进制日志(binlog):关于二进制日志,它记录了数据库所有执行的 DDL 和 DML 语句(除了数据查询语句 select、show 等),以事件形式记录并保存在二进制文件中。
还有两个 InnoDB 存储引擎特有的日志文件:
重做日志(redolog):重做日志至关重要,因为它们记录了对于 InnoDB 存储引擎的事务日志。
回滚日志(undolog):回滚日志同样也是 InnoDB 引擎提供的日志,顾名思义,回滚日志的作用就是对数据进行回滚。当事务对数据库进行修改,InnoDB 引擎不仅会记录 redolog,还会生成对应的 undolog 日志;如果事务执行失败或调用了 rollback,导致事务需要回滚,就可以利用 undolog 中的信息将数据回滚到修改之前的样子。
20.binlog 和 redo log 有什么区别?
binlog 会记录所有与数据库有关的日志记录,包括 InnoDB、MyISAM 等存储引擎的日志,而
redolog 只记 InnoDB 存储引擎的日志。
记录的内容不同,binlog 记录的是关于一个事务的具体操作内容,即该日志是逻辑日志。而
redolog 记录的是关于每个页(Page)的更改的物理情况。
写入的时间不同,binlog 仅在事务提交前进行提交,也就是只写磁盘一次。而在事务进行的过程
中,却不断有 redo ertry 被写入 redo log 中。写入的方式也不相同,redolog 是循环写入和擦除,binlog 是追加写入,不会覆盖已经写的文件。
21.一条更新语句怎么执行的了解吗?
更新语句的执行是 Server 层和引擎层配合完成,数据除了要写入表中,还要记录相应的日志。

- 执行器先找引擎获取 ID=2 这一行。ID是主键,存储引擎检索数据,找到这一行。如果 ID=2
这一行所在的数据页本来就在内存中,就直接返回给执行器;否则,需要先从磁盘读入内存,然后再返回。
- 执行器拿到引擎给的行数据,把这个值加上 1,比如原来是 N,现在就是 N+1,得到新的一行数
据,再调用引擎交叉写入这行新数据。
- 引擎将这行新数据更新到内存中,同时将这个更新操作记录到 redolog 里面,此时 redolog 处
于 prepare 状态。然后告知执行器执行完成了,随时可以提交事务。
执行器生成这个操作的 binlog,并把 binlog 写入磁盘。
执行器调用引擎的提交事务交叉,引擎把刚刚写入的 redolog 改成提交(commit)状态,更新
完成。
从上图可以看出,MySQL 在执行更新语句的时候,在服务层进行语句的解析和执行,在引擎层进行数据的提取和存储;同时在服务层对 binlog 进行写入,在 InnoDB 内进行 redolog 的写入。
不仅如此,在对 redolog 写入时有两个阶段的提交,一是 binlog 写入之前prepare状态的写入,二是 binlog 写入之后commit状态的写入。
22.那为什么要两阶段提交呢?
为什么要两阶段提交呢?直接提交不行吗?
我们可以假设不采用两阶段提交的方式,而是采用“单阶段”进行提交,即要么先写入 redolog,后写入 binlog;要么先写入 binlog,后写入 redolog。这两种方式的提交都会导致原先数据库的状态和被恢复后的数据库的状态不一致。
先写入 redolog,后写入 binlog:
在写完 redolog 之后,数据此时具有crash-safe能力,因此系统崩溃,数据会恢复成事务开始之前的状态。但是,若在 redolog 写完时候,binlog 写入之前,系统发生了宕机。此时 binlog 没有对上面的更新语句进行保存,导致当使用 binlog 进行数据库的备份或者恢复时,就少了上述的更新语句。从而使得id=2这一行的数据没有被更新。

先写入 binlog,后写入 redolog:
写完 binlog 之后,所有的语句都被保存,所以通过 binlog 复制或恢复出来的数据库中 id=2 这一行的数据会被更新为 a=1。但是如果在 redolog 写入之前,系统崩溃,那么 redolog 中记录的这个事务会无效,导致实际数据库中id=2这一行的数据并没有更新。

简单说,redolog 和 binlog 都可以用于表示事务的提交状态,而两阶段提交就是让这两个状态保持逻辑上的一致。
23.redo log 怎么刷入磁盘的知道吗?
redolog 的写入不是直接落到磁盘,而是在内存中设置了一片称之为redologbuffer的连续内存空间,也就是redo 日志缓冲区。

什么时候会刷入磁盘?
在如下的一些情况中,logbuffer 的数据会刷入磁盘:
logbuffer 空间不足时
logbuffer 的大小是有限的,如果不停的往这个有限大小的 logbuffer 里塞入日志,很快它就会被填满。如果当前写入 logbuffer 的 redo 日志量已经占满了 logbuffer 总容量的大约一半左右,就需要把这些日志刷新到磁盘上。
事务提交时在事务提交时,为了保证持久性,会把 logbuffer 中的日志全部刷到磁盘。注意,这时候,除了本事务的,可能还会刷入其它事务的日志。
后台线程输入有一个后台线程,大约每秒都会刷新一次logbuffer中的redolog到磁盘。
正常关闭服务器时
触发 checkpoint 规则
重做日志缓存、重做日志文件都是以块(block)的方式进行保存的,称之为重做日志块(re dolog
block), 块的大小是固定的 512 字节。我们的 redolog 它是固定大小的,可以看作是一个逻辑上的
loggroup,由一定数量的logblock组成。

它的写入方式是从头到尾开始写,写到末尾又回到开头循环写。
其中有两个标记位置:
writepos是当前记录的位置,一边写一边后移,写到第 3 号文件末尾后就回到 0 号文件开头。checkpoint是当前要擦除的位置,也是往后推移并且循环的,擦除记录前要把记录更新到磁盘。

当write_pos追上checkpoint时,表示 redolog 日志已经写满。这时候就不能接着往里写数据了,需要执行checkpoint规则腾出可写空间。
所谓的checkpoint 规则,就是 checkpoint 触发后,将 buffer 中日志页都刷到磁盘。