目录

【MySQL】InnoDB中一条更新语句的执行流程

SQL语句执行流程

一条SQL语句的执行,需要经过连接器、分析器、优化器、执行器和存储引擎等模块。

连接器管理着MySQL和客户端的连接,分析器将SQL语句分析成语法树,优化器会选择合适的执行计划,执行器根据执行计划来调用存储引擎提供的接口。

SQL语句的总体执行流程都是一样,但不同类型的语句,执行器做出的操作会有所不同。

Buffer Pool

Buffer PoolInnoDB存储引擎内部的一块内存组件,用于缓存各种数据。

更新数据时,会先检查对应行是否在Buffer Pool缓存中。如果不在,就从磁盘读入缓存。

如果Buufer Pool中有了所需数据,InnoDB会对该行加写锁,从而避免其他事务并发修改。

undo log

undo log是回滚日志,通过该日志可以将数据回滚到指定版本,事务回滚和一致性视图都应用到了它。

更新数据时,InnoDB会将旧的数据信息写入undo log

脏数据

写完undo log后,InnoDB会更新Buffer Pool中的记录。

这时,内存和磁盘中的数据是不一致的,所以称内存中的数据是脏数据,需要后续写入磁盘。

MySQL有一个后台线程,该线程会在某些时间点,将Buffer Pool中的脏数据刷新到磁盘中。

redo log

redo logInnoDB特有的日志,用于记录数据页的修改信息。通常情况下,该日志会被存放在名为redo log buffer的内存缓冲区中。

事务提交前,InnoDB会将修改信息写入redo log,并在redo log中添加prepare标记,表示准备提交事务。

如果在脏数据刷新到磁盘之前,MySQL崩溃了,此时内存中的数据会丢失。有了redo logMySQL重启后就能实现数据恢复。

当然,服务崩溃后redo log buffer中的redo log也会被清除。因此,提交事务时需要将redo log写入磁盘。

参数innodb_flush_log_at_trx_commit控制着redo log的刷盘策略。该参数有3个值:

  • 0:提交事务时,不会把日志写入磁盘,而是每隔一秒进行写入。

  • 1:提交事务时,会将日志写入磁盘。

  • 2:提交事务时,只会将日志写入操作系统的文件缓存,操作系统崩溃时该缓存会丢失。

bin log

bin logserver层的日志,与存储引擎无关,记录的是逻辑性的日志,比如“将满足条件的记录更新为指定值”。

提交事务之前,除了会写redo log,还会写bin log

bin log也有一个刷盘策略,由参数sync_binlog控制:

  • 参数为0时,每次提交事务,都只是将日志写入操作系统的文件缓存中。

  • 参数为1时,每次提交事务都会将日志写入磁盘。

  • 参数为n时,表示每提交n个事务才写入一次磁盘,其余时间只写入文件缓存。

事务提交

事务提交后,会在redo log中写入commit标记。

事务准备提交时,会先写redo log,并标记为prepare状态。然后写bin log,再提交事务,最后将redo log改为commit状态。该流程就是“两阶段提交”。

在主备架构中,bin log会被用于进行主备库的数据同步。如果bin log已经写入,则备库就会执行对应事务。“两阶段提交”的设计目的,是为了保证数据一致性。

如果写了redo log并标记为repare状态,崩溃重启后,MySQL会根据redo log中的XIDbin log进行查找。如果找到对应日志,就应用redo log进行数据恢复,否则丢弃该日志。

如果写了redo log并标记为commit状态,崩溃重启后,MySQL会直接利用该日志进行数据恢复。

至此,一条更新语句就执行结束了。