在执行一个update语句之前,同样需要把语句从客户端发送到服务器,所以在执行一个update语句时同样要经过连接器阶段,接收到update语句后,在分析器阶段会对语句进行词法分析和语法分析,在该阶段可以解析出语句是什么类型的,语句是否符合语法规则,以及选取耗时更短的执行方案,在执行器阶段则会使用执行引擎提供的接口找出需要更新的行,并且更新其中的数据。
    从上面的过程可以看到,执行update语句的过程和select语句大体上相同,但是由于update语句会向磁盘中写入数据从而更改数据的内容,为了及时持久化数据以及对操作进行备份,在Mysql中引入了redo log(重做日志)文件和bin log(归档日志)文件。
    为什么要引入redo log(重做日志)文件呢?这是因为如果我们每次更新都找到磁盘中数据行对应的位置,并更改其中的数据,显然效率是很低的,为什么这样做效率很低呢?而如果我们采用了redo log(重做日志)文件,当我们执行更新语句时,就不需要具体的在磁盘上更改这些数据了,只需要把哪些数据行进行了哪种更改记录在redo log(重做日志)文件中,并且在内存中更改相应的数据行就可以了(前提是相应的数据行已经读入到了内存中,否则还要先把数据行读取到内存中,是这样吗,我都找到数据行的位置了,把它读取到内存中了,为什么不直接把它写入到磁盘中呢?),这时update语句就算执行完成了,当Mysql比较空闲的时候Mysql就会把redo log文件中的内容具体更改到磁盘上的数据行中。
    那么这个时候就会出现这么一个问题,如果更新语句执行的很频繁,把redo log文件写满了怎么办?redo log文件是一个固定大小、循环使用的文件,也就是说在向redo log文件中写入数据时,会先从头写,写到最后再重新回到开头继续写,所以我们要保证一件事,在把redo log文件中的内容具体更改到磁盘上的数据行之前,不能被新数据覆盖,redo log文件中的内容并不是一次性应用到磁盘上的,而是应用一部分,把指针后移一部分,指针指向的是没有应用到磁盘上的数据行更改的起点,在向redo log文件中追加记录时,同样会更新记录追加点的位置。当记录追加点的位置赶上没有应用到磁盘上的数据行更改的起点时,Mysql就会停止执行更新语句,先进行刷脏过程,给redo log文件腾出空间。
    可以想到,即使Mysql在某个时刻突然宕机了,很多数据没有保存到磁盘上,我们也可以根据redo log文件中的内容来恢复数据库中的数据。如果宕机的时候,某个更新语句还没有把更改记录到redo log(重做日志)文件中,我们就认为这个语句并没有被执行,在恢复数据时也不会恢复这条语句的执行结果。那么我们怎么知道在执行哪个命令的时候出现宕机了呢?这个没办法知道,但是我们可以知道在宕机之前执行的最后一条命令是什么,也就是在redo log文件中最后一条更改记录对应的命令。
    为什么要引入bin log(归档日志)文件呢?因为有的时候我们要对Mysql数据库进行移植,所以对执行过的语句要进行备份。
    既然引入了两个日志文件,那么这两个日志文件就要保持一致性,那么这两个日志文件是如何保证一致性的呢?首先要分析执行一个update语句会经过的过程,假设这个更新语句是update T set c=c+1 where ID=2,其中ID是主键索引,前面的过程就不重复叙述了,直接到执行器阶段,在执行器阶段首先调用执行引擎的”取满足条件的第一行”接口,通过b+树直接找到id=2的数据行,如果id=2的数据行所在的数据页此时正在内存中,就直接把这个数据行返回给Mysql的执行器阶段,如果此时数据行不在内存中,就要先从磁盘中把这个数据行所在的数据页读取到内存中,再把这个数据行返回给Mysql的执行器。
    Mysql的执行器在拿到执行引擎返回的数据后,会根据语句的内容对数据行中的数据进行修改,修改之后再调用执行引擎的接口把数据写入到磁盘上。
    那么把数据写入到磁盘上的执行引擎接口是怎么实现的呢?执行引擎首先会在redo log文件中记录在哪个数据行上进行了什么修改,然后向Mysql的执行器返回一个语句执行完成的回复,在向redo log文件写入成功后,我们就说此时redo log进入了prepare阶段,在向执行器返回回复之后,Mysql的执行器会把这个语句记录到bin log文件中,记录到bin log文件后执行器会调用存储引擎的提交事务接口,提交事务后redo log就进入了commit阶段。
    那么如果我们不按照这个过程来执行的话,会发生什么呢?如果我们不给redo log文件设置阶段,那么会发生什么呢?有两个日志文件,redo log文件和bin log文件,所以要么是先写入redo log文件后写入bin log文件,要么是先写入bin log文件后写入redo log文件,总共只有这两种执行顺序,先考虑第一种情况,如果我们在写入redo log文件后,bin log文件还没有写完时,Mysql发生了宕机,那么会发生什么呢?首先根据redo log文件我们能在磁盘上恢复所有丢失的数据,但是这时我们使用bin log文件来恢复数据时,在宕机时执行的语句就丢失了。如果是先写入bin log文件,后写入redo log文件,在写入redo log文件时Mysql发生了宕机,那么会发生什么呢?使用bin log文件恢复的数据,比使用redo log文件恢复的数据,多了在宕机时执行的语句。
    什么时候才会用到bin log文件?当我们在进行某次误操作之后就需要使用bin log文件来回滚数据,或者是在搭建备库的时候,都会用到bin log文件,那么搭建备库是怎么用到bin log文件的呢?首先找到最近的全量备份,然后再执行bin log文件中记录的语句来实现与主库的数据一致。全量备份是什么?怎么生成全量备份的?多久做一次全量备份?
    怎么使用bin log文件把数据库回滚到某个时间点?数据库管理员(DBA)所说的半个月内可恢复是什么意思?意思是当前数据库可以回滚到半个月内的任一时间点,那么怎么做到这一点呢?很简单,我们只需要每半个月进行一次全量备份,然后使用bin log文件记录这半个月内执行的语句即可,这么说是不是半个月之前的bin log文件我们就可以删除了?当我们需要把数据库恢复到半个月内的某个时间点时,只需要以全量备份为起点,然后找出bin log文件中从全量备份时间点到指定时间点之间执行过的语句,交给Mysql服务器再执行一遍,就可以把数据恢复到指定时间点了。这么说是不是bin log在记录语句的同时,也记录了执行语句的时间?
    既然有两个日志文件,那么这两个文件有什么区别呢?首先redo log日志文件是InnoDB引擎提供的,bin log日志文件是Mysql自带的,redo log日志文件是循环写的,而bin log日志文件是追加写的,追加写指的是当文件的大小超过某个值时,bin log文件会生成一个新的文件,而不是会覆盖原有的文件,它们的作用也不相同,redo log文件的作用是快速持久化语句的更改,bin log文件的作用是对执行过的语句进行存档,那么bin log文件有几种保存格式呢?bin log文件有三种保存格式,第一种是raw格式,raw格式指的是,第二种是statement格式,第三种是mixed格式,
    在进行全量备份时可以灵活的选择周期时间,那么一天进行一次全量备份和一周进行一次全量备份相比有什么优势呢?一天一备的优点在于恢复某个时刻数据的最长时间更短,在一天一备的情况下,最多需要应用一天的bin log日志文件,如果是一周一备,最多就需要应用一周的bin log日志文件,但是一天一备存在的问题是更频繁的进行全量备份必然会占用更多的存储空间,所以要根据业务的重要性选择合适的全量备份周期。全量备份越频繁恢复到目标状态的时间就越短,所以如果业务越重要,全量备份的周期就尽可能短。
    全量备份文件多久删除一次?