MySql更新语句的执行过程

流程

在这里插入图片描述
这是之前的查询的时候使用的流程图,更新语句的流程图和查询也是很相似的

  1. 客户端获取连接器的连接
  2. 由于是更新操作,这时候会清除所有的缓存,如果对表更新比较濒繁,缓存使用起来还是很坑的
  3. 之后分析器来分析语法是否有问题
  4. 优化器这时候就会开始决定使用哪个索引
  5. 之后执行器操作,和查找不同的是,更新流程涉及到两个重要的日志模块,redo log(重做日志)和 binlog(归档日志)

redo log

我们的常规想法是,如果一个数据更新了的话,直接将其写入到磁盘中;但是如果数据量大的话,操作频繁的话,整个过程IO成本、查找成本都很高。

所以简单的做法就是将其先写入缓存中,等到一定数据量的时候在将其写入磁盘,这样就可以避免上面的问题;

Mysql中采取了类似的方法,称作为WAL技术,WAL的全称是Write-Ahead Logging,它的关键点就是先写日志,再写磁盘,就是先将操作数据,记录在内存中,等到空闲时候,再将其写入磁盘中;如果内存被写满了的话,那么MySql会停下来将其内存中的操作都写入磁盘中,在继续操作;

InnoDB的redo log是固定大小的,比如可以配置为一组4个文件,每个文件的大小是1GB,那么这块“粉板”总共就可以记录4GB的操作。从头开始写,写到末尾就又回到开头循环写,如下面这个图所示。
在这里插入图片描述
write pos是当前记录的位置,一边写一边后移,写到第3号文件末尾后就回到0号文件开头。

checkpoint是当前要擦除的位置,也是往后推移并且循环的,擦除记录前要把记录更新到数据文件。

正常的流程是,write pos不断将操作的记录写入文件中,而checkpoint将日志的操作读取进入磁盘中;两者之前空的位置 就可以不断记录新的数据操作;

有了redo log,InnoDB就可以保证即使数据库发生异常重启,之前提交的记录都不会丢失,这个能力称为crash-safe。这样就算断电后,也可以通过日志记录和磁盘的数据来复原原来的数据;

binlog

介绍

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

有两份日志的原因是因为,最开始的时候MySql是没有InnoDB引擎的。最早使用的是MyISAM,但是MyISAM没有cash-safe的能力,binlog日志只能用于归档。而InnoDB是另一个公司以插件形式引入Mysql的,既然只依靠binglog是没有cash-safe能力的,所以InnoDB使用另一套日志系统 ------也就是redo log来实现crash - safe 能力

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

  1. redo log是InnoDB引擎特有的;binlog是MySQL的Server层实现的,所有引擎都可以使用。

  2. redo log是物理日志,记录的是“在某个数据页上做了什么修改”;binlog是逻辑日志,记录的是这个语句的原始逻辑,比如“给ID=2这一行的c字段加1 ”。

  3. redo log是循环写的,空间固定会用完;binlog是可以追加写入的。“追加写”是指binlog文件写到一定大小后会切换到下一个,并不会覆盖以前的日志。

更新语句执行流程

update语句的执行流程图,图中浅色框表示是在InnoDB内部执行的,深色框表示是在执行器中执行的。
在这里插入图片描述
流程:

  1. Service层中的执行器会根据索引或者查询的条件,让InnoDB引擎查询需要修改的列,看是否在内存中,如果在直接读取出来,如果不在将其在磁盘中查找出来,将数据返回给Service层

  2. Service层执行器 获取到引擎数据后,把这个值加上1,比如原来是N,现在就是N+1,得到新的一行数据,再调用引擎接口写入这行新数据。

  3. 引擎将新数据更新到内存中去时,同时将这个更新操作记录到redo log里面,此时redo log处于prepare状态。然后告知执行器执行完成了,随时可以提交事务。

  4. 执行器生成这个操作的binlog,并把binlog写入磁盘。

  5. 执行器调用引擎的提交事务接口,引擎把刚刚写入的redo log改成提交(commit)状态,更新完成。

两阶段提交

为什么采用 binlog和redo log的两段式同时提交后,才会完成这个事务的那?因为是为了防止在处理这个事务过程中宕机了,如果没有这个两阶段提交,那么binlog记录的和redo log记录的会有不同,这样后期处理的时候,两边的日志记录不一样,后期恢复的时候,那么数据库的状态就有可能和用它的日志恢复出来的库的状态不一致。

这种两阶段提交的概念不止用于mysql中,在分布式项目中,用于处理分布式事务,多个更新数据库的操作,一一都成功没有问题的时候,最后才统一提交给数据库

数据库删库后恢复

开发口中说的最多的是就是删库跑路了,那么删库后真的就跑路了吗?不是的是可以操作恢复的;

binlog会记录所有的逻辑操作,并且是采用“追加写”的形式。如果需要恢复的话,那么需要提交备份好binlog日志;。

当需要恢复到指定的某一秒时,比如某天下午两点发现中午十二点有一次误删表,需要找回数据,那你可以这么做:

首先,找到最近的一次全量备份,如果你运气好,可能就是昨天晚上的一个备份,从这个备份恢复到临时库;
然后,从备份的时间点开始,将备份的binlog依次取出来,重放到中午误删表之前的那个时刻。
这样你的临时库就跟误删之前的线上库一样了,然后你可以把表数据从临时库取出来,按需要恢复到线上库去。

这个恢复情况取决于备份情况,系统需要定期做整库备份。这里的“定期”取决于系统的重要性,可以是一天一备,也可以是一周一备

总结

redo log(物理日志)可以理解为InnoDB在写入磁盘的时候采用的一个缓存机制,而binlog(逻辑日志)类似于总账本,记录数据库所有的操作记录;

redo log用于保证crash-safe能力。innodb_flush_log_at_trx_commit这个参数设置成1的时候,表示每次事务的redo log都直接持久化到磁盘。这个参数我建议你设置成1,这样可以保证MySQL异常重启之后数据不丢失。

sync_binlog这个参数设置成1的时候,表示每次事务的binlog都持久化到磁盘。这个参数我也建议你设置成1,这样可以保证MySQL异常重启之后binlog不丢失。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值