MySQL45讲:一条update语句是怎样执行的

首先创建一张表;

create table T(ID int primary key,c int);

如果要更新ID=2这行+1;应该这样写

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

执行这句操作首先还是要与数据库建立连接这是连接器的工作。
在一个表进行更新操作时,这张表的缓存就会失效。

接下来分析器会对这条跟新语句进行语法和词法分析,如果有问题就会报错提示。然后优化器会决定使用ID的索引情况,最后执行器负责执行,找到这行然后更新。

与查询操作不同的是,更新操作涉及到两个重要的日志模块。redo log(重做日志),bin log(归档日志)。如果接触到MySQL这两个日志是必学的。

redo log

如果每一次的更新操作都需要写进磁盘,然后磁盘也要找到对应的那条记录,然后在更新,这个过程IO成本、查找成本都很高。为了解决这个问题,MySQL的设计者就用了类似于酒店掌柜的黑板记录来提升效率。
WAL技术简称Write-Ahead Logging ,他的关键就是先写日志再写磁盘。写磁盘的时间并不是固定的,他是等到系统比较空闲的时候才写入磁盘。

当一条记录需要更新的时候,InnoDB引擎就会把记录写进redo log里面,并更新内存。这个时候就算更新完成了。同时,InnoDB引擎会在适当的时候将这个操作记录更新到磁盘中。

还有需要注意的是,InnoDB的redo log 是固定大小的,比如以组分为4个文件,每个文件大小是1GB,那么这个日子就可以记录4GB的操作。从头开始写,写到结尾再从头开始写。是一个循环。

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

要理解crash-safe这个概念,可以想象赊账的例子,只要赊账记录在了黑板上或卸载账本上,即使店长忘记了,但也有黑板上或账本上的明确数目。

bin log

上面所说的redo log 是InnoDB引擎独有的日志,而Server层也有自己的日志,称为bin log(归档日志)。

其实bin log日志出现的时间比redo log早,因为最开始MySQL是没有InnoDB存储引擎的,5.5之前是MyISAM。但是MyISAM没有crash-safe的能力,binlog日志只能永固归档。而InnoDB是另一个公司使用的一套日志系统来实现crash-safe能力。

两种日志的区别

  1. redo log 是InnoDB独有的;bing log 是MySQL的Server层实现的,所有引擎都可以使用。
  2. redo log 是物理日志,记录的是在某个数据页改动了哪些;bin log 是逻辑日志,记录的是SQL语句具体操作。
  3. redo log 是循环写的,空间固定会用完;binlog是可以追加写入的。追加写是指binlog文件写到一定大小后会切换到下一个,并不会覆盖以前的日志。

update语句内部流程

  1. 执行器先找到引擎ID=2这行,ID是主键,引擎直接用树搜索找到这一行。如果ID=2这行数据被就在内存中那就不需要再调入内存直接返回给执行器;否则需要先从磁盘读入内存,然后再返回。
  2. 执行器拿到引擎给的行数据,把行值+1,得到新的一行数据,在调用引擎接口写入这行新数据。
  3. 引擎将这行新数据更新到内存中,同时将这个更新操作记录到redo log里面,此时redo log处于prepare状态。然后告知执行器执行完成了,随时可以提交事务。
  4. 执行器生成这个操作的bin log,并把bin log 写入磁盘。
  5. 执行器调用引擎的提交事务接口,引擎把刚刚写入的redo log改成提交状态,更新完成。
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
    在这里插入图片描述

上图中浅绿色的是在InnoDB引擎中执行的,墨绿色是在Server层完成的。

如果不使用“两阶段提交”,那么数据库的状态就有可能和用它的日志恢复出来的库的状态不一致。

原文地址:https://www.cnblogs.com/itjiangpo/p/14181398.html