一个普通的语句的执行流程是 连接器 分析器 优化器 执行器最后到达了存储引擎

对于更新,亦是如此

我们拿一个简单的更新语句来看

update user set age = age+1 where id = 1;

整体的执行流程:

首先是连接器连接,这是固定的

然后会将这个表相关的缓存进行废弃

然后分析器会根据语法和词法进行分析得到这是个更新语句,然后优化得到是否使用索引,最后更新

但是在更新之后,涉及到了日志模块,这是整个MySql数据备份最重要的地方,在MySql中,必然会接触到redo log和binlog

1.首先是redo log日志

redo log 日志简单来说就是,如果每次更新的操作都会从硬盘中读出数据然后写完在放进去,这种IO操作让人无法接受,于是引出了redo log

将更新的数据先放在redolog里面,然后到时间再更新内存,这个技术又名WAL技术,WAL技术全名是Write-Ahead Logging,就是先写日志,在写磁盘

当然会有额外情况出现,如果某次日志存储满了,那就必须先写入磁盘,将日志文件空出来就能继续写入了,像InnoDB的redo log ,就可以配置为一组4个文件,然后redolog可以循环写,一边写入,一边存入磁盘

图片
.

check point是写入到磁盘了的点, write pos是写入日志的店

这样一追一赶,保证了在发生了异常重启之后,都不会丢失数据 称为 crash-safe

当然,redolog是引擎层维护的,在其之上,还有着Server层的日志,binlog归档日志

2.binlog

MySql自带日志,不支持crash-safe能力,不同于redolog

可以让所有的引擎使用,而且是逻辑日志,会记录语句的执行逻辑,比如 给ID=2的字段c加一

binlog不会像redolog一样写完,而是会写满一个生成一个新的,每个都是单独的文件的binlog

最终,一个更新语句的执行为

首先找到ID=2的数据,也就是一个select的语句,然后拿到这个数据,进行更新,调用执行引擎去写入,然后将其更新到内存中,写入redoLog,此时redoLog处于prepare状态,然后写入binlog

最后调用语句的事务提交,将文件中的redolog改为commit状态

图片

这样整个更新过程中,就会拆成两个阶段 prepare和commit

那么,是否可以利用两阶段提交来做一些事情呢,比如恢复数据库

首先说恢复数据库,必须有biglog日志,恢复到哪一个时刻,就是先恢复最近的全量备份,然后依次读取binlog,这样就能保证一样了

为何要做到如此的提交的方式,利用反证法,或者反过来

先写redolog 在写biglog,那么如果数据崩溃了,redolog写完了,binlog中没有,那么恢复的时候,是利用binlog恢复的,会少一条数据

如果先写binlog,在写redolog,那么恢复的时候,由于 redolog还没写,崩溃恢复以后这个事务无效,所以这一行 c 的值是 0。但是 binlog 里面已经记录了“把 c 从 0 改成 1”这个日志。所以,在之后用 binlog 来恢复的时候就多了一个事务出来,恢复出来的这一行 c 的值就是 1,与原库的值不同。

而且,数据库的主从复制,就是依赖于binlog的

最后,如果想要精确的保存数据,可以吧innodb_flush_log_at_trx_commit设置为1,保证每次事务都会持久化到磁盘

同样,sync_binlog设置为1,会将每次的事务binlog都持久化到磁盘,也可以保证重启后binlog的完整性

在备份恢复过程中,如果是一天一备的话,最坏情况需要一天的binlog,

如果是一周一备,则需要一周的binlog了

发表评论

邮箱地址不会被公开。 必填项已用*标注