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

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

前面了解了一个查询语句的执行流程,并介绍了执行过程中涉及的处理模块,一条查询语句的执行过程一般是经过连接器、分析器、优化器、执行器等功能模块,最后达到engine

这里分析一个update语句的流程

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

更新语句

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

查询语句的那一套流程,更新语句也是同样会走一遍

执行语句前要先连接db--连接器的工作

在一个表上有更新的时候,跟这个表有关的查询缓存会失效,所以这条语句就会把表T上所有缓存结果都清空--不建议使用查询缓存的原因

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

与查询流程不一样的,更新流程还涉及两个重要的日志模块:redo logbinlog

redo log

mysql里,如果每一次的更新操作都需要写进磁盘,然后磁盘也要找到那条对应的记录,然后再更新,整个过程io成本、查找成本都很高,为了解决这个问题,在mysql里使用WALwrite-ahead loggin,日志先行,关键点就是先写日志、再写磁盘。

扫描二维码关注公众号,回复: 6435418 查看本文章

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

Innodbredo log是固定大小,从头开始,写到末尾就又回到开头循环写,有了redo loginnodb就可以保证即使数据库发生异常重启,之前提交的记录都不会丢失,这个功能称为crash-safe

binlog

mysql整体来看,一块是server层,主要是mysql功能层面的事情;另一块是引擎层,负责存储相关的具体事宜,redo log就是innodb特有的日志,而server层的日志,就是binlog

两种日志的不同点

--1 redo loginnodb引擎特有的,binlogmysql server层实现的,所有引擎都可以使用。

--2 redo log是物理日志,记录的是”在某个数据页上做了什么修改”binlog是逻辑日志,记录的是这个语句的原始逻辑。

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

更新update的流程

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

--2 执行器拿到engine给的行数据,把这个值加上1,比如是n>n+1,得到新的一行数据,在调用引擎接口写入这行新数据

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

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

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

两阶段提交

怎样让数据库恢复到7天内任意一秒的状态?

binlog会记录所有的逻辑操作,并且是采用追加写的形式,如果保存了最近一个月的binlog,同时系统有定期的整库备份,当需要恢复到指定的某一秒时,比如某条下午两点发现中午十二点有一次误删表,需要找回数据,可以这么做

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

--2 从备份的时间点开始,将备份的binlog依次取出来,重放到中午误删表之前的那个时刻。

这样临时库就跟误删之前的线上一样,然后可以把表数据从临时库取出来,按需要恢复到线上库去。

由于redo logbinlog是两个独立的逻辑,如果不用两阶段提交,要么是先写完redo log再写binlog,或者反过来的顺序,看看有什么问题

--1 先写redo log后写binlog。假设redo log完成,binlog还没有写完,mysql异常重启,由于redo log写完之后,即使系统崩溃,已让能够把数据恢复。

但是由于binlog没写完就crash,这时候binlog没有这条update语句,之后备份日志的时候,存起来的binlog就没有这条语句,如果用binlog恢复的话,就会丢失之前的更新。

--2先写binlog后写redo log。如果在binlog之后carsh,还没来得及写redo log,崩溃恢复后这个update更新就无效,但是binlog里面已经记录了更新,这样用binlog来进行恢复就会导致不一致,同时也会导致备库的不一致。

简单说,redo logbinlog都可以用于表示事务的提交状态,而两阶段提交就是让这两个状态保持逻辑上的一致

redo log用于保证crash-safe的能力,innodb_flush_log_at_trx_commit=1表示每次事务的redo log都直接持久化到磁盘,建议设置为1sync_binlog=1,表示每次事务的binlog都持久化到磁盘,也建议设置为1.--1模式

猜你喜欢

转载自www.cnblogs.com/yhq1314/p/11011219.html