更新语句执行过程
查询语句的执行过程更新语句都会执行一遍,先连接器进行连接,再执行分析器分析sql,再执行优化器优化获取id过程,执行器负责具体执行,读取要更新的行到内存中,执行SQL操作后,更新到内存,然后写redo log,写bin log,此时即为完成。后续InnoDB会在合适的时候把此次操作的结果写回磁盘。
具体过程:
- 执行器先找存储引擎获取需要更新的数据。若使用到了索引,则会通过所引述查到id,然后如果id所在行所在数据也在内存中,直接返回给执行器;否则需要先从磁盘读入内存,再返回。
- 执行器拿到引擎给的行数据,把值更新后,得到新的一行数据,再调用引擎接口写入这行新数据。
- 引擎将新数据更新到内存中,同时将这个更新操作记录到redo log里面,此时redo log处于prepare状态。然后告知执行器已完成。
- 执行器生成这个操作的binlog,并把binlog写入磁盘。
- 执行器调用引擎的提交事务接口,引擎把刚写入的redo log改为commit状态,更新完成。
WAL技术(Write-Ahead Logging)
WAL技术(Write-Ahead Logging):就是先写日志,再写磁盘;具体来说,当有一条记录需要更新的时候,InnoDB引擎就会先把记录写redo log里面,并更新内存,这个时候就是更新完成了。InnoDB引擎会在适当的时候,将这个操作记录更新到磁盘里面,而这个更新往往是在系统比较空闲的时候。
重要的日志模块:redo log(重做日志)
redo log是重做日志。主要用于MySQL异常重启后的一种数据恢复手段,确保了数据的一致性。 归根到底是MySQL为了实现WAL机制的一种手段。因为MySQL进行更新操作,为了能够快速响应,所以采用了异步写回磁盘的技术,写入内存后就返回。但是会存在crash后内存数据丢失的隐患,而redo log具备crash safe能力。
redo log是InnoDB引擎特有的日志系统。redo log属于物理日志,记录的是数据页上的修改(磁盘上数据的物理变化) 。redo log是固定大小的,从头开始写,写到末尾就又回到开头循环,如下图所示:
write pos是当前记录的位置,一边写一边后移,写到3号文件末尾就回到0号文件开头。check point 是当前要擦除的位置,也是往后推移并且循环的,擦除记录之前要把记录更新到数据文件。
write pos和check point 之间是空余的部分,可以用来记录新的操作。如果 write pos 追上 check point 表示空间满了,需要先吧记录更新到数据文件,再记录新的操作。
有了redo log,InnoDB就可以保证即使数据库发生异常重启,之前提交的记录都不会丢失,这个能力称之为 crash-safe(崩溃恢复) 。
重要的日志模块:binlog(归档日志)
binlog是Server层的日志,所有引擎都可以使用。
binlog记录的是逻辑日志,有两种模式,statemenet格式是记录sql语句,row格式会记录行的内容,记两条,更新前和更新后。
binlog是可以追加写入的,不会覆盖以前的日志。
怎么让数据库恢复到半个月内任意一秒的状态?
- 先找到最近的一次全量备份,把这个备份恢复到临时库。
- 再从备份的时间点开始,将备份binlog一次取出来,重放到想要恢复的那个时刻。
- 然后就可以把表从临时库取出,按需要恢复到线上库。
两阶段提交
若没有两阶段提交,并且在update时写完第一个日志,第二个日志还没写完期间发生了crash,会出现什么情况?
- 先写 redo log 后写 binlog。 redo log 写完之后,系统即使崩溃,仍然能够把数据恢复回来,所以恢复后这一行 c 的值是 1。但是由于 binlog 没写完就 crash 了,这时候 binlog 里面就没有记录这个语句。因此,之后备份日志的时候,存起来的 binlog 里面就没有这条语句。然后你会发现,如果需要用这个 binlog 来恢复临时库的话,由于这个语句的 binlog 丢失,这个临时库就会少了这一次更新,恢复出来的这一行 c 的值就是 0,与原库的值不同。
- 先写 binlog 后写 redo log。 如果在 binlog 写完之后 crash,由于 redo log 还没写,崩溃恢复以后这个事务无效,所以这一行 c 的值是 0。但是 binlog 里面已经记录了“把 c 从 0 改成 1”这个日志。所以,在之后用 binlog 来恢复的时候就多了一个事务出来,恢复出来的这一行 c 的值就是 1,与原库的值不同。
redolog和binlog是如何实现的:
-
先写入redo log日志做prepare阶段。此时日志写入磁盘,状态为prepare
-
写入bin log日志。
- 若写入成功,提交事务,redo log更新状态为commit
- 若写入失败,回滚事务,redo log回滚日志
-
若提交事务后 redo log更新时发生crash,在数据恢复时redo log会以bin log记录的为准(通过事务ID关联);若bin log记录为事务提交,则redo log将日志更新为 commit。
物理日志和逻辑日志
- 逻辑日志可以给别的数据库,别的引擎使用,已经大家都讲得通这个“逻辑”;
- 物理日志就只有“我”自己能用,别人没有共享我的“物理格式”
重要参数
innodb_flush_log_at_trx_commit: 建议设为1 表示每次事务的redo log都直接持久化到磁盘(是把日志写入磁盘,且是顺序写)。这样可以保证MySQL异常重启之后数据不丢失。
sync_binlog: 建议设为1,表示每次事务的binlog都持久化到磁盘。这样可以保证MySQL异常重启之后binlog不丢失。
问题及答案
- redo log的概念是什么? 为什么会存在.
- redo log是重做日志。主要用于MySQL异常重启后的一种数据恢复手段,确保了数据的一致性。归根到底是MySQL为了实现WAL机制的一种手段。因为MySQL进行更新操作,为了能够快速响应,所以采用了异步写回磁盘的技术,写入内存后就返回。但是会存在crash后内存数据丢失的隐患,而redo log具备crash safe能力。
- 什么是WAL(write-ahead log)机制, 好处是什么.
- WAL机制是写前日志,也就是MySQL更新操作后在真正把数据写入到磁盘前先记录日志。好处是不用每一次操作都实时把数据写盘,就算crash后也可以通过redo log重放恢复,所以能够实现快速响应SQL语句。
- redo log 为什么可以保证crash safe机制.
- 因为redo log是每次更新操作完成后,就一定会写入的,如果写入失败,这说明此次操作失败,事务也不可能提交。redo log内部结构是基于页的,记录了这个页的字段值变化,只要crash后读取redo log进行重放就可以恢复数据。(因为redo log是循环写的,如果满了InnoDB就会执行真正写盘)
- binlog的概念是什么, 起到什么作用, 可以做crash safe吗?
- bin log是归档日志,属于MySQL Server层的日志。可以起到全量备份的作用。当需要恢复数据时,可以取出某个时间范围内的bin log进行重放恢复。但是bin log不可以做crash safe,因为crash之前,bin log可能没有写入完全MySQL就挂了。所以需要配合redo log才可以进行crash safe。
- binlog和redolog的不同点有哪些?
- bin log是Server层,追加写,不会覆盖,记录了逻辑变化,是逻辑日志。redo log是存储引擎层,是InnoDB特有的。循环写,满了就覆盖从头写,记录的是基于页的物理变化,是物理日志,具备crash safe操作。
- 物理一致性和逻辑一直性各应该怎么理解?
- 物理一致性是数据库在底层存储的层面上保证数据没有损坏或丢失;逻辑一致性是确保数据在逻辑和语义上的正确性,符合业务规则和约束。
- 执行器和innoDB在执行update语句时候的流程是什么样的?
- 执行器在优化器选择了索引后,调用InnoDB读接口,读取要更新的行到内存中,执行SQL操作后,更新到内存,然后写redo log,写bin log,此时即为完成。后续InnoDB会在合适的时候把此次操作的结果写回到磁盘。
- 如果数据库误操作, 如何执行数据恢复?
- 数据库在某一天误操作,就可以找到距离误操作最近的时间节点前的bin log,重放到临时数据库里,然后选择当天误删的数据恢复到线上数据库。
- 什么是两阶段提交, 为什么需要两阶段提交, 两阶段提交怎么保证数据库中两份日志间的逻辑一致性(什么叫逻辑一致性)?
- 两阶段提交就是对于三步操作而言:1.prepare阶段 2. 写入bin log 3. commit redo log在写入后,进入prepare状态,然后bin log写入后,进入commit状态,事务可以提交。 如果不用两阶段提交的话,可能会出现bin log写入之前,机器crash导致重启后redo log继续重放crash之前的操作,而当bin log后续需要作为备份恢复时,会出现数据不一致的情况。所以需要对redo log进行回滚。 如果是bin log commit之前crash,那么重启后,发现redo log是prepare状态且bin log完整(bin log写入成功后,redo log会有bin log的标记),就会自动commit,让存储引擎提交事务。
- 如果不是两阶段提交, 先写redo log和先写bin log两种情况各会遇到什么问题?
- 先写redo log,crash后bin log备份恢复时少了一次更新,与当前数据不一致。先写bin log,crash后,由于redo log没写入,事务无效,所以后续bin log备份恢复时,数据不一致。