一条SQL更新语句是如何执行的?( 三 )


现在回答之前的问题 。因为刷脏是随机I/O,而记录日志是顺序I/O(连续写的),顺序I/O效率更高,本质上是数据集中存储和分散存储的区别 。因此先把修改写入日志文件,在保证了内存数据的安全性的情况下,可以延迟刷盘时机,进而提升系统吞吐 。
3.3 redo日志的系统变量redo日志位于MySQL数据目录下,默认有ib_logfile0和ib_logfile1两个文件,如下图所示 。

一条SQL更新语句是如何执行的?

文章插图
可以发现,两个redo日志文件的大小都是50331648,默认48MB 。为什么这个大小是固定的呢?因为如果我们要使用顺序I/O,就必须在申请磁盘空间的时候一次性决定申请的空间大小,这样才能保证申请的磁盘空间在地址上的连续性 。
这也就决定了redo日志的旧数据会被覆盖,一旦文件被写满,就会触发Buffer Pool脏页到磁盘的同步,以腾出额外空间记录后面的修改 。
可以通过以下指令查看redo日志的系统属性 。
mysql> show variables like 'innodb_log%';
+-----------------------------+----------+
Variable_name | Value |
+-----------------------------+----------+
innodb_log_buffer_size | 16777216 |
innodb_log_checksums | ON |
innodb_log_compressed_pages | ON |
innodb_log_file_size | 50331648 |
innodb_log_files_in_group | 2 |
innodb_log_group_home_dir | ./ |
innodb_log_write_ahead_size | 8192 |
+-----------------------------+----------+
参数名称含义innodb_log_file_size指定每个redo日志文件的大小,默认48MBinnodb_log_files_in_group指定redo日志文件的数量,默认2innodb_log_group_home_dir指定redo文件的路径,如果不指定,则默认为datadir目录
介绍到这里,读者朋友可以发现,我们刚才探索的是如何让已经提交的事务保持持久化,但是如果某些事务偏偏在执行到一半的时候出现问题怎么办?
事务的原子性要求事务中的所有操作要么都成功,要么都失败,不允许存在中间状态 。就好比我在写这篇文章的时候,会时不时地敲一下ctrl+Z返回到上一步或者过去好几步之前的状态,MySQL也需要“留一手”,把事务回滚时需要的东西都记录下来 。
比如,插入数据的时候,至少应该把新增的这条记录的主键的值记录下来,这样回滚的时候只要把这个主键值对应的记录删除就可以了 。
MySQL又一个鼎鼎大名的日志——undo日志,正式登场!
4. undo日志undo log(撤销日志或回滚日志)记录了事务发生之前的数据状态,分为insert undo log和update undo log 。
如果修改数据时出现异常,可以用 undo log来实现回滚操作(保持原子性) 。可以理解为undo日志记录的是反向的操作,比如INSERT操作会记录DELETE,UPDATE会记录UPDATE之前的值,和redo日志记录在哪个物理页面做了什么操作不同,所以这是一种逻辑格式的日志 。
undo日志和redo日志与事务密切相关,被统称为「事务日志」 。
一条SQL更新语句是如何执行的?

文章插图
关于undo日志,我们目前只需要了解这么多即可
5. SQL更新语句的执行总结——初版有了事务日志之后,我们来简单总结一下更新操作的流程,这是一个简化的过程 。
name 原值是chanmufeng 。
update t_user_innodb set name ='chanmufeng1994' where id = 1;
  1. 事务开始,从内存(Buffer Pool)或磁盘取到包含这条数据的数据页,返回给 Server 的执行器;
  2. Server 的执行器修改数据页的这一行数据的值为 chanmufeng1994;
  3. 记录 name=chanmufeng 到undo log;
  4. 记录 name=chanmufeng1994到redo log;
  5. 调用存储引擎接口,记录数据页到Buffer Pool(修改 name=penyuyan);
  6. 事务提交 。
6. binlog日志之前我们讲过,从MySQL整体架构来看,其实可以分成两部分
  • Server 层,它主要做的是 MySQL功能层面的事情,比如处理连接、解析优化等;
  • 存储引擎层,负责存储相关的具体事宜 。
redo日志是InnoDB存储引擎特有的日志,而Server层也有自己的日志,称为 binlog(归档日志),它可以被所有存储引擎使用 。
6.1 为什么有了redo日志还需要 binlog?我想你可能会问出这个问题,实际上,更准确的问法是为什么有了binlog还需要有redo日志?主要有以下几个原因 。
  1. 因为最开始MySQL里并没有InnoDB存储引擎 。MySQL自带的引擎是MyISAM,但是 MyISAM没有崩溃恢复的能力,InnoDB后来以插件的形式被引入,顺便带来了redo日志;


    推荐阅读