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

一条更新SQL语句的执行过程html

提出问题

UPDATE student SET score = score + 1 WHERE uid = 666; 以上就是一条最简单的SQL更新语句,想要知道上面这句SQL语句是怎么执行的先要了解MySQL数据库的逻辑架构。mysql

UPDATE语句也不例外的执行这个流程,先链接数据库(链接器),而后将SQL语句进行词法分析,并检测SQL语法(分析器),而后优化对应的查询操做(优化器),最后真正的去执行这个语句(执行器)。

具体到上面的UPDATE语句,先取出uid=666的全部行,而后将这些行的score字段的值加1,并写入内存中。接下来的过程与查询语句的查询流程就不同了,查询语句只须要返回查询结果便可,可是更新语句须要去真的修改数据库中的数据,因此更新语句相对来说要复杂一些。sql

说到SQL的更新语句就不得不提到重作日志(redo log)归档日志(binlog),这两个日志在MySQL中起到了巨大的做用,这两个日志的相互配合也是颇有意思的设计,接下来就要详细给你们讲下这两种日志的做用、它们是如何工做的、以及它们之间的相互配合。shell

redo log

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

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语句执行的含义。

上面讲了这么多这两种日志的含义,下面简单总结下这两种日志的一些区别:

  • redo log是一种物理日志,记录是这个页作了什么改动,而binlog是逻辑日志,记录是sql语句的原始逻辑。
  • redo log的文件大小是固定的,会循环写入文件,因此会覆盖以前的日志。而binlog是追加写,不会覆盖以前的日志。
  • redo log是InnoDB引擎层的日志,而binlog是server层的日志。

有同窗会问,为何要搞两个日志呀?

咱们知道MySQL最开始默认的引擎是MyASIM引擎,根本就不存在crash-safe的问题,binlog只是用来作归档的。在MySQL5.5.5以后将InnoDB做为默认的存储引擎,这样InnoDB就拥有了crash-safe的能力,在MySQL的架构中,引擎是以插件的形式存在的,InnoDB引擎不是MySQL数据库必须的,因此也就好理解redo log也不是MySQL数据库必须的日志。

这也就好理解为何要搞两个日志,一个是server层,一个是引擎层,他们负责不一样的功能,相互合做。

那具体这两个日志是怎么合做的呢?他们怎么保证数据的一致性呢?

两阶段提交

先说下两阶段提交的具体过程:

  • UPDATE语句的结果写入内存,同时将这个操做写入redo log,此时redo log处于prepare状态,并告知执行器随时能够提交事物。
  • 执行器生成这个操做的binlog,并写入binlog日志。
  • 执行器通知将以前处于prepare状态改成commit状态,更新完成。

两个阶段提交保证了redo log和binlog的一致性。 下面来分析下若是不是两个阶段提交会发生什么?

先写redo log后写binlog

若是先写redo log再写binlog的话,当redo log写完的时候发生了crash,此时binlog里面是没有记录的。这时候发生重启,redo log会恢复crash的语句,可是若是用这产生时的binlog去恢复数据库就会丢失这条记录,此时两个日志恢复的数据库数据就产生了差别。

先写binlog后写redo log

若是是先写binlog后写redo log,当写完binlog的时候发生了crash。这时候发生重启,redo log中还没写,此时异常重启后这个事务是无效的,因此没法恢复,可是binlog中有这条数据,当用此时的binlog文件去恢复数据库的时候,就会比当前的数据库数据多一条记录。

从上面就能够明白,若是不用两阶段提交就有可能出现两个日志状态不一致。

相关文章
相关标签/搜索