前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >一条更新语句如何执行

一条更新语句如何执行

作者头像
小土豆Yuki
发布2020-07-02 14:48:30
3730
发布2020-07-02 14:48:30
举报
文章被收录于专栏:洁癖是一只狗洁癖是一只狗

一条更新语句如何执行呢,他和查询语句一样吗,我们先看一张图

其实更新语句和查询语句的流程是基本一样的,但是他其中不一样的是涉及两个日志模块,也就是我们经常提到的redo log(重做日志)和binlog(归档日志)。

往往我们在开发的日常中,DBA同事经常在我们不小心误删除了某些数据,DBA同事总能帮我们找回来,其实他们也是利用这两个日志。

redo log

我们现在回忆一下以前酒馆的记账的模式,酒馆里有一个黑板,当酒店人多的时候,掌柜的就会把账临时记录在黑板上,当人少的时候在把账目记录在账本上,当然也可以直接把账目记录在账本上,但是这样就比较麻烦,还要在账本上找到对应的记录,再去修改记录。显然易见我们利用黑板效率更高一点,这里的黑板相当于我们数据库的redo log。

上面说的黑板和账本的配合就是我们常说的WAL(WriteAhead Logging)技术,先写日志,在写入磁盘.

具体来说,当我们要更新一条记录的时候,我们先把他写入redo log中,并更新内存,当InnoDb适当的时候把这个操作放到磁盘中,正如酒店空闲的时候把黑板的账目记录在账本上。

但是往往酒店的黑板是固定大小的,黑板写满了,我就不得把记录写到账本上,然后腾出新的空间,我们的redo log也是一样的,也是有有固定大小的,比如我们可以配置4个文件,每一个文件可以放置4G大小的数据,重头开始写,循环写,正如下图

check_point记录我们擦除的位置,write_pos记录我们写到的位置,一边写一边向后移动,当check_point和write_pos重合的时候,我就得把check_point向后移动。

因此有了redo log,当数据库发生异常重启,我们也能保证之前提交的记录不会丢失,当然我们理解一个概念crash-safe,就如账面酒店关门歇业几天,当开业的时候,依然可以通过账目和黑板明确账目.

binlog

我们之前看过数据库分为两个模块,存储引擎和server,上面说到的redo log日志是InnnoDB的特有日志,而server也有自己的日志,他就是binlog日志

当然我们会想到为什么有了binglog日志,还要有redo log,那是因为binglog日志是归档的作用,没有crash-safe的能力,因此使用插件的形式引入了redo log,

他们的不同点

redo log 是物理日志,记录在数据库做了什么,binlog日志是逻辑日志,记录了语句的原始逻辑

redo log是InnoDB存储引擎独有的,binglog是在server层,所有存储引擎都可以使用,

redo log是循环使用的,binLog日志是追加的

一条更新语句整体的执行流程如下

代码语言:javascript
复制
update T set c=c+1 where id =2
  1. 执行器先获取Id=2,id是主键,利用树索引找到这一行,这条数据刚好在内存中,直接返回,如果没在,执行器到磁盘读取,更新到内存,然后在返回
  2. 执行器获取到这条数据之后,更新c的值,然后把调用引擎的接口写入
  3. 引擎把这条数据更新到内存中,然后记录在redo log中,此时redo log状态为prepare,此时告诉引擎,随时可以提交事务
  4. 执行器生成这动作的binlog,并写入磁盘
  5. 执行器执行引擎的事务接口,提交事物,redo log的状态改成提交状态(commit),更新完成

我们很多人疑惑为什么redo log开始的状态prepare状态,当提交完事务在改成commit,也就是我们常说的二阶段提交。

二阶段提交

为什么要使用二阶段提交呢,是为了保持两份日志的一致性,我们先回顾一下数据库如何恢复数据,我们知道binlog日志是追加的形式,我们每年或每天都会进行备份,当我需要恢复数据的时候,如下操作

  1. 拿到最近一次的备份,从这个备份恢复到临时库中
  2. 然后从这个备份时间点,开始把binlog的日志恢复到有问题的时间点

这个时候就和误删出之前的数据一样了,这样可以在把需要的数据放到数据库中.

我们再来说为什么要使用二阶段提交,不如使用反证法证明一下

如果不用二阶段提交,一个日志写完,在写第二个日志,当第二个日志,没有写入,就直接crash宕机了。会有什么结果

先写redo日志,在写binlog日志,当redo写完之后,binlog没有来的及写入,此时宕机,我们之前就说过,crash之后,我们依然可以恢复到1(c+1)之后的数据

但是,binlog的这条更新记录没有写入,因此之后的备份,就会少这样的逻辑,如果要使用这个binlog日志恢复临时库的时候,数据还是之前的数据c=0的的数据,会导致与源库不一致

先写binlog,在写入redo日志,当redo还没有写入之后,宕机了,此时redo 日志还是c=0的状态,但是当binlog使用的时候,恢复出多了一个事物,就会导致与源库的不一致。

可以看出不适用二阶段提交,会导致用日志恢复出的数据库和源库不一致,当然你可能任务宕机的概率很低,其实当你需要扩容的时候,也会用到日志搭建从库,这样备份出的数据库会和主库的状态不一致.

简单来说,redo log和 binlog都可以表示事物的状态,而二阶段提交保证了两个日志的状态保持一致。

最后,我们可以设置innodb_flush_log_at_trx_commit为1,保证每次事务的redolog都持久化磁盘,保证redolog的crash-safe,保证数据不会丢失,也可以设置sync_binlog设置为1,这样保证了数据库重启之后保证binlog不会丢失.

希望此文对大家有所帮助,也希望大家持续关注转载。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-06-28,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 洁癖是一只狗 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
数据库
云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档