一个普通的语句的执行流程是 连接器 分析器 优化器 执行器最后到达了存储引擎
对于更新,亦是如此
我们拿一个简单的更新语句来看
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了