MYSQL的日志系统

mysql的更新过程涉及到两个重要的日志模块redo log和binlog

mysql> create table t(id int primary key, c int);
update t set c=c+1 where id=2;

redo log

在mysql中如果每一次更新都需要写磁盘的话,然后磁盘需要找到那条记录,然后再更新整个IO成本,查询成本都很高,所以Innodb引擎就会把记录先写到redo log里面,并更新内存,同时Innodb会在适当的时候把操作记录写到磁盘里面,往往在系统空闲的时候这么做。

这里写到redo log也是写到磁盘的,但是和更新过程不同的是,更新是在磁盘上随机IO,而写redo log是顺序IO,效率更高。

如果需要更新的数据很多,redo log大小不够了,需要将之前的日志更新到数据文件。有了 redo log,InnoDB 就可以保证即使数据库发生异常重启,之前提交的记录都不会丢失,这个能力称为 crash-safe。也就是mysql 和 innodb是独立分开的 mysql重启对在innodb中的redo log 不影响。

binlog

redo log是Innodb引擎特有的日志,而mysql server层也有自己的日志binlog(归档日志)
这两种日志的区别

  1. redo log是Innodb引擎特有的,binlog是Server层的,所有引擎都可以用

  2. redo log是物理日志,记录在数据页做什么修改,binlog是逻辑日志比如给id=2的记录的c字段-1

  3. redo log是循环写的,binlog是追加写的,文件大小写完之后,下个文件继续写,不覆盖
    执行器和innodb执行更新操作的流程

  4. 执行器从引擎找到id=2这一行,如果在内存中直接返回给执行器

  5. 执行器给这行数据加1,调用引擎写入新数据

  6. 更新新数据到内存,并写入redo log,此时redo log处于prepare阶段,告知执行器执行完成

  7. 执行器生成这个操作的binlog,把binlog写入磁盘

  8. 执行器调用引擎的提交事务接口,redo log处于comit阶段,结束
    MYSQL的日志系统_第1张图片
    注意这里的prepare和comit都是redo log的状态不是事务状态。

两阶段提交

为什么需要两阶段提交
1.先写redo log再写binlog,已经写完redo log但是mysql异常重启,binlog还没写完,redo log 写完之后,系统即使崩溃,仍然能够把数据恢复回来,所以恢复后这一行 c 的值是 1。但是由于 binlog 没写完就 crash 了,这时候 binlog 里面就没有记录这个语句。恢复出来c的值是0
2.险些binlog再写redo log如果在 binlog 写完之后 crash,由于 redo log 还没写,崩溃恢复以后这个事务无效,所以这一行 c 的值是 0。但是 binlog 里面已经记录了“把 c 从 0 改成 1”这个日志。所以,在之后用 binlog 来恢复的时候就多了一个事务出来,恢复出来的这一行 c 的值就是 1,与原库的值不同。
两阶段提交,这是为了让两份日志之间的逻辑一致

你可能感兴趣的:(关系型数据库,mysql,数据库,数据结构)