02|一条MySQL更新语句是如何执行的

02|一条MySQL更新语句是如何执行的

update T set c=c+1 where ID=2;

其实一条更新语句的执行操作和查询语句的执行操作基本相同->一条SQL查询语句是如何查询的?,唯一不同的是一条更新语句在执行过程中需要涉及到两个日志操作(redo log、binlog)。步骤如下:

  1. 连接器:建立一个链接

  2. 分析器:词法优化、语法优化

  3. 优化器:给出该条SQL语句执行方案

  4. 执行器:如下

  • 执行器先找引擎取 ID=2 这一行。ID 是主键,引擎直接用树搜索找到这一行。如果 ID=2 这一行所在的数据页本来就在内存中,就直接返回给执行器;否则,需要先从磁盘读入内存,然后再返回。
  • 执行器拿到引擎给的行数据,把这个值加上 1,比如原来是 N,现在就是 N+1,得到新的一行数据,再调用引擎接口写入这行新数据。
  • 引擎将这行新数据更新到内存中,同时将这个更新操作记录到 redo log 里面,此时 redo log 处于 prepare 状态。然后告知执行器执行完成了,随时可以提交事务。
  • 执行器生成这个操作的 binlog,并把 binlog 写入磁盘。
  • 执行器调用引擎的提交事务接口,引擎把刚刚写入的 redo log 改成提交(commit)状态,更新完成。

02|一条MySQL更新语句是如何执行的_第1张图片

redo log

首先我们思考一个问题,那就是当我们每执行一条更新操作,MySQL是否都会将更新的数据立即写入磁盘?答案是:否

因为如果每一次的更新操作都需要写进磁盘,然后磁盘也要找到对应的那条记录,然后再更新,整个过程 IO 成本、查找成本都很高。因此为了解决这个问题,MySQL设计者采用了WAL技术。具体来说就是当有一条记录需要更新时,InnoDB引擎就会先把这条记录写入到redo log中,并且更新内存,此时更新就算完成了。同时,InnoDB引擎会在合适的时候将记录写到磁盘中,而这个操作往往是在系统比较空闲的时候去做。

但是可能会存在一些问题,要是系统一直不空闲怎么办?redo log日志的容量是多大?

redo log日志容量是固定的,比如可以配置为一组 4 个文件,每个文件的大小是 1GB,那么这块日志总共就可以记录 4GB 的操作。当日志写不下了,那就会将最开始的那块日志更新到数据文件,同时对这块日志进行擦除,进而腾出空间继续写入。

有了 redo log,InnoDB 就可以保证即使数据库发生异常重启,之前提交的记录都不会丢失,这个能力称为 crash-safe。

binlog

MySQL 整体来看,其实就有两块:一块是 Server 层,它主要做的是 MySQL 功能层面的事情;还有一块是引擎层,负责存储相关的具体事宜。上面我们聊到的 redo log (重做日志)是 InnoDB 引擎特有的日志,而 Server 层也有自己的日志,称为 binlog(归档日志)。

这两种日志有以下三点不同。

  1. redo log 是 InnoDB 引擎特有的;binlog 是 MySQL 的 Server 层实现的,所有引擎都可以使用。
  2. redo log 是物理日志,记录的是“在某个数据页上做了什么修改”;binlog 是逻辑日志,记录的是这个语句的原始逻辑,比如“给 ID=2 这一行的 c 字段加 1 ”。
  3. redo log 是循环写的,空间固定会用完;binlog 是可以追加写入的。“追加写”是指 binlog 文件写到一定大小后会切换到下一个,并不会覆盖以前的日志。

两阶段提交

为什么需要两阶段提交呢?这是为了让两份日志之间的逻辑一致。

  • 先写 redo log 后写 binlog

当写完redo log日志后,binlog 还没有写完的时候,MySQL 进程异常重启。这个时候我们仍然可以通过redo log日志将数据恢复,这样看起来并没有什么问题。但是我们可以想一下,当我们之后备份数据的时候,备份的是bin log日志,如果需要用这个 binlog 来恢复临时库的话,由于这个语句的 binlog 丢失,这个临时库就会少了这一次更新,数据就会与原值不一致。

  • 先写binlog后写redo log日志

如果在 binlog 写完之后 crash,由于 redo log 还没写,崩溃恢复以后这个事务无效。但是 binlog 里面已经记录了该条修改日志。所以,在之后用 binlog 来恢复的时候就多了一个事务出来,与原库的数据不一致。

小结

  • Bin log 用于记录了完整的逻辑记录,所有的逻辑记录在 bin log 里都能找到,所以在备份恢复时,是以 bin log 为基础,通过其记录的完整逻辑操作,备份出一个和原库完整的数据。

  • redo log用于崩溃恢复,当MySQL崩溃重启以后,能够通过redo log将数据正确恢复到崩溃前的值。

你可能感兴趣的:(MySQL进阶,mysql,数据库,java)