下面是一个表的创建语句,这个表有一个主键id和一个整型字段c:

create table t(id int primary key,c int);

如果要将 id = 2 这一行的值加 1,sql语句就会这么写:

update t set c = c+1 where id =2;

上一篇文章介绍过sql语句几本的执行链路,首先可以确定的说,查询语句的流程,更新语句也是同样的会走一遍。

我们执行语句之前都要先连接数据库,这是连接器的工作。

前面有说过,当更新一条语句的时候,跟这个表相关的查询缓存会失败,所以现在这条语句会把表t上所有缓存结果都清空。这就是不建议使用查询缓存的原因。

接下来分析器会通过词法和语法解析知道这是一条更新语句。优化器决定使用id这个索引,然后执行器负责执行,找到这一行,然后更新。

与查询流程不一样的是,更新流程还涉及到两个重要的日志模块,也就是今天要讨论的主角:redo log(重做日志)和binglog(归档日志)。

重要的日志模块:redo log

用一篇文章来解释《孔乙己》,酒店掌柜有一个粉板,专门用来记录客人的赊账记录。如果赊账的人不多,那么他可以把顾客名和账目写在板上。但如果赊账但人多了,粉板总会有记不住的时候,这个时候掌柜一定还有一个专门记录赊账的账本。

如果有人要赊账或者还账的话,掌柜一般有两种做法:

1.一种是直接把账本翻出来,把这次赊的账加上去或者扣除调;

2.另一种做法是先在粉板上记下来这次的账,等打烊以后再把账本翻出来核算。

在生意红火柜台很忙的时候,掌柜一定选择后者,因为前者操作实在太麻烦了。首先你得找到这个人的赊账总额那条记录。你想想,密密麻麻几十页,掌柜要找到那个名字,可能还得带上老花镜慢慢找,找到以后再拿出来计算,最后再把结果写到账本上。

这整个过程想想都麻烦,还是先在粉板上记一下方便。如果每次没有粉板的帮助,每次记账都得翻账本,效率是不是很低?

同样,在mysql里也有这个问题,如果每次的更新操作都需要写进磁盘,然后磁盘也要找到对应的那条记录,然后再更新,整个过程io成本 查找成本都很高。为了解决这个问题,mysql设计者就用了类似酒店掌柜的思路来提升更新效率。

而粉板和账本配合的过程,其实就是mysql里经常说到的WAL技术,全称是Write-Ahead Logging,它的关键点就是先写日志,再写磁盘,也就是先写粉本,等不忙的时候再写账本。

具体来说,当有一条记录需要更新的时候,innodb引擎就会先把记录写到redo log(粉板)里面,并更新到内存,这个时候更新就算完成了,同时innodb引擎会在适当到时候 将这个操作记录更新到磁盘,而这个更新往往是在系统比较空闲的时候做,这就像打烊以后掌柜做的事。

如果今天赊账的不多,掌柜可以等打烊后再整理。但如果某天赊账的特别多,粉板写满了怎么办?这个时候掌柜只好放下手中的活儿,把粉板中的一部分赊账记录更新到账本中,然后把这些记录从粉板上擦掉,为记录新账腾出空间。

innodb的redo log是固定大小的,比如可以配置一组4个文件,每个文件的大小是1gb,那么这块粉板总共就可以记录4gb的操作。从头开始写,写到末尾就又回到开头循环写。如下图一样

write pos是当前记录的位置,一边写一边后移,写到弟3号文件末尾后就回到0号文件开头。checkpoint是当前要擦出的位置,也是往后推移并且循环的,擦出记录钱要把记录更新到数据文件。

write pos 和 checkpoint之间的是粉板上还空着的部分,可以用来记录新的操作。如果wite pos追上checkpoint,表示粉板已经满了,这时候不能再执行新的更新,得先停下来擦掉一些记录,把checkpoint推进一下。

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

要理解crash-safe这个概念,可以想想我们前面赊账记录的例子。只要赊账记录记在了粉板上或者写在了账本上,之后即使掌柜忘记了,比如突然停业几天,恢复生意后依然可以通过账本和粉板上的数据明确赊账账目。

重要的日志模块:binlog

mysql整体看分为两块:一是server层,它主要做的是mysql功能层面的事情,二是引擎层,负责存储相关的具体事宜。上面我们聊到粉板redo log是innodb引擎特有的日志,而server层也有自己的日志,称为binlog(归档日志)。

为什么会有两份日志呢?

因为最开始mysql里并没有innodb引擎。mysql自带的引擎是myisam,但是myisam没有crash-safe能力,binlog日志只能用来归档。而innodb以插件的形式引入到mysql的,既然只依靠binlog是没有crash-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文件写到一定大小后会切换到下一个,并不会覆盖以前的日志。

有了对这两个日志的概念性理解,我们再来看执行器和innodb引擎在执行这个简单的update语句时的内部流程。

1.执行器先找引擎取ID =2 这一行。ID是主键,引擎直接用树搜索找到这一行。如果ID = 2这一行所在的数据页本来就在内存中,就直接返回给执行器;否则,需要先从磁盘读入内存,然后再返回。

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

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

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

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

两阶段提交

为什么必须有两阶段提交呢?这是为了让两份日志之间的逻辑一致。要说明这个问题,我们得从文章开头的那个问题说起:怎样让数据库回复到半个月内任意一秒的状态?

binlog会记录所有的逻辑操作,并且是采用追加写的形式。

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

首先,找到最近的一次全量备份,如果运气好,可能就是昨天晚上的一个备份,从这个备份恢复到临时

日志系统:一条sql更新语句是如何执行的?--Mysql45讲笔记记录 打卡day2的更多相关文章

  1. 2 日志系统:一条sql更新语句是如何执行的?

    2 日志系统:一条sql更新语句是如何执行的? 前面了解了一个查询语句的执行流程,并介绍了执行过程中涉及的处理模块,一条查询语句的执行过程一般是经过连接器.分析器.优化器.执行器等功能模块,最后达到e ...

  2. 02 | 日志系统:一条SQL更新语句是如何执行的? 学习记录

    <MySQL实战45讲>02 | 日志系统:一条SQL更新语句是如何执行的? 学习记录http://naotu.baidu.com/file/ad320c7a0e031c2d6db7b5a ...

  3. 一条SQL更新语句是如何执行的

    文章首发于公众号「蝉沐风」,认真写好每一篇文章,欢迎大家关注交流 这是图解MySQL的第2篇文章,这篇文章会通过一条SQL更新语句的执行流程让大家清楚地明白: 什么是InnoDB页?缓存页又是什么?为 ...

  4. 02 | 日志系统:一条SQL更新语句是如何执行的?

    前面我们系统了解了一个查询语句的执行流程,并介绍了执行过程中涉及的处理模块.相信你还记得,一条查询语句的执行过程一般是经过连接器.分析器.优化器.执行器等功能模块,最后到达存储引擎. 那么,一条更新语 ...

  5. mysql实战45讲读书笔记(二) 一条SQL更新语句是如何执行的 极客时间

    前面我们系统了解了一个查询语句的执行流程,并介绍了执行过程中涉及的处理模块.相信你还记得,一条查询语句的执行过程一般是经过连接器.分析器.优化器.执行器等功能模块,最后到达存储引擎. 那么,一条更新语 ...

  6. 《Mysql 一条 SQL 更新语句是如何执行的?(Redo log)》

    一:更新流程 - 对于更新来说,也同样会根据 SQL 的执行流程进行. -  - 连接器 - 连接数据库,具体的不做赘述. - 查询缓存 - 在一个表上有更新的时候,跟这个表有关的查询缓存会失效. - ...

  7. (转)一条SQL更新语句是如何执行的

    名词 MySQL 里经常说到的 WAL 技术,Write-Ahead Logging 第一个日志模块 redo log 也叫日志重写,是InnoDB 引擎特有的日志 - write pos and c ...

  8. 一条SQL语句是如何执行的?--Mysql45讲笔记记录 打卡day1

    写在前面的话:回想以前上班的时候,空闲时间还是挺多的,但是都荒废了.如今找工作着实费劲了.但是这段时间在极客时间买了mysql45讲,就好像发现了新大陆一样,这是我认真做笔记的第一天,说实话第一讲我已 ...

  9. 一文读懂一条 SQL 查询语句是如何执行的

    2001 年 MySQL 发布 3.23 版本,自此便开始获得广泛应用,随着不断地升级迭代,至今 MySQL 已经走过了 20 个年头. 为了充分发挥 MySQL 的性能并顺利地使用,就必须正确理解其 ...

随机推荐

  1. ruby rails

    http://www.zhihu.com/question/19552402   作者:陈振宇链接:http://www.zhihu.com/question/19552402/answer/1236 ...

  2. uva 10806 Dijkstra, Dijkstra. (最小费最大流)

    uva 10806 Dijkstra, Dijkstra. 题目大意:你和你的伙伴想要越狱.你的伙伴先去探路,等你的伙伴到火车站后,他会打电话给你(电话是藏在蛋糕里带进来的),然后你就能够跑去火车站了 ...

  3. 光流(optical flow)和openCV中实现

    转载请注明出处! ! ! http://blog.csdn.net/zhonghuan1992 光流(optical flow)和openCV中实现 光流的概念:        是Gibson在195 ...

  4. WPF新手之如何将数据绑定到TreeView

    看过许多例子,全是绑定到类的,没人说如何绑定到某个对象,偏偏我这个绝对的新手就是要绑定到一个对象,只能自己摸索了: 首先要将数据绑定到容器,有以下几个默认条件:①元数据必须包装在List或者Obser ...

  5. Codeforces Round #422 (Div. 2) A. I'm bored with life 暴力

    A. I'm bored with life     Holidays have finished. Thanks to the help of the hacker Leha, Noora mana ...

  6. Spring中的IOC容器(学习笔记)

    如何将Bean配置到Spring的Bean容器中 通过xml配置文件: Bean实现类来自第三方类库:如“DataSource”等      需要命名空间配置如:context,aop,mvc等   ...

  7. cat /proc/cpuinfo | awk -F: '/name/{print $2}' | uniq -c

    cat /proc/cpuinfo | awk -F: '/name/{print $2}' | uniq -c

  8. Android Studio解决导入项目非常慢

    Android Studio比Eclipse ADT有巨大的优势.Android Studio原生支持使用Gradle来构建项目,使用动态语言Groovy定义项目构建的过程,避免了build.xml文 ...

  9. HDFS运维和优化

    常见问题 下面列举HDFS运行过程中可能出现的常见问题及解决方法,这些问题一般都会在日志中出现的相应的记录.Incompatible clusterIDs in … :namenode cluster ...

  10. 超全!整理常用的iOS第三方资源(转)

    超全!整理常用的iOS第三方资源 一:第三方插件 1:基于响应式编程思想的oc 地址:https://github.com/ReactiveCocoa/ReactiveCocoa 2:hud提示框 地 ...