一条更新SQL语句的执行过程html
UPDATE student SET score = score + 1 WHERE uid = 666;
以上就是一条最简单的SQL更新语句,想要知道上面这句SQL语句是怎么执行的先要了解MySQL数据库的逻辑架构。mysql
具体到上面的UPDATE语句,先取出uid=666的全部行,而后将这些行的score字段的值加1,并写入内存中。接下来的过程与查询语句的查询流程就不同了,查询语句只须要返回查询结果便可,可是更新语句须要去真的修改数据库中的数据,因此更新语句相对来说要复杂一些。sql
说到SQL的更新语句就不得不提到重作日志(redo log) 和归档日志(binlog),这两个日志在MySQL中起到了巨大的做用,这两个日志的相互配合也是颇有意思的设计,接下来就要详细给你们讲下这两种日志的做用、它们是如何工做的、以及它们之间的相互配合。shell
redo log是为了解决crash-safe问题而产生的,是一种物理日志,咱们知道数据库是用来存储数据的,crash-safe问题对于数据库来讲是很是重要的,在开启redo log以后MySQL的异常重启以前提交的数据都不会丢失,这样就能保证异常crash后数据不会丢失。数据库
redo log是InnoDB引擎层的一种日志,是用来记录这个页"作了什么改动"。在MySQL中常常会说道WAL技术,WAL的全称是Write Ahead Logging,WAL的核心思想就是日志先行,举个例子,执行一条更新语句,InnoDB就会先把记录写到redo log里面,而后更新到内存,等到系统比较空闲的时候再写入磁盘。redo log的文件大小是固定的,是经过循环写的 实现的。ubuntu
有了redo log就能保证InnoDB即便发生异常重启也不会丢失数据,这种能力也叫作crash-safe的能力架构
binlog是一种逻辑日志,是Server层的一种日志,记录了全部的sql语句,主要是用来配合备份来恢复数据库的,只要咱们有最近一次的备份和这期间完整的binlog就可以恢复数据库了。 下面咱们来简单看下binlog文件,我是ubuntu系统,这个文件是放在/var/log/mysql/
文件夹下面的,优化
从上面的图片咱们能看到文件名字是依次增长的,与redo log的循环写不一样,binlog是追加写的。 咱们执行下面的命令行就能看到binlog记录的sql语句是什么样的,还有一些binlog文件内容的参照 官方文档操做。ui
sudo mysqlbinlog /var/log/mysql/mysql-bin.000002 --base64-output=DECODE-ROWS --verbose —verbose
复制代码
执行的结果以下图所示:spa
从上图来看很清晰的能看懂这个update语句执行的含义。
上面讲了这么多这两种日志的含义,下面简单总结下这两种日志的一些区别:
有同窗会问,为何要搞两个日志呀?
咱们知道MySQL最开始默认的引擎是MyASIM引擎,根本就不存在crash-safe的问题,binlog只是用来作归档的。在MySQL5.5.5以后将InnoDB做为默认的存储引擎,这样InnoDB就拥有了crash-safe的能力,在MySQL的架构中,引擎是以插件的形式存在的,InnoDB引擎不是MySQL数据库必须的,因此也就好理解redo log也不是MySQL数据库必须的日志。
这也就好理解为何要搞两个日志,一个是server层,一个是引擎层,他们负责不一样的功能,相互合做。
那具体这两个日志是怎么合做的呢?他们怎么保证数据的一致性呢?
先说下两阶段提交的具体过程:
两个阶段提交保证了redo log和binlog的一致性。 下面来分析下若是不是两个阶段提交会发生什么?
若是先写redo log再写binlog的话,当redo log写完的时候发生了crash,此时binlog里面是没有记录的。这时候发生重启,redo log会恢复crash的语句,可是若是用这产生时的binlog去恢复数据库就会丢失这条记录,此时两个日志恢复的数据库数据就产生了差别。
若是是先写binlog后写redo log,当写完binlog的时候发生了crash。这时候发生重启,redo log中还没写,此时异常重启后这个事务是无效的,因此没法恢复,可是binlog中有这条数据,当用此时的binlog文件去恢复数据库的时候,就会比当前的数据库数据多一条记录。
从上面就能够明白,若是不用两阶段提交就有可能出现两个日志状态不一致。