-
Notifications
You must be signed in to change notification settings - Fork 0
Description
更新语句的执行流程
更新语句的执行流程和查询语句的执行流程类似,区别在于更新语句会使查询语句的查询缓存失效,同时还会涉及到两个日志模块:redo log (重做日志)和 bin log (归档日志)
redo log(重做日志)
当有一条记录需要更新时,InnoDB 引擎就会先把记录写到 redo log 中,并更新内存,此时更新算是完成了,之后,InnoDB 引擎会在适当的时候将记录写入磁盘中。
这里涉及到 WAL 技术(Write-Ahead Logging),先写日志,再写磁盘
redo log 的大小是固定的,比如可以配置为一组 4 个文件,每个文件的大小是 1 GB,那么 redo log 可以记录 4 GB 的操作。从头开始写,写到末尾就又回到开头循环写,如下图:
write pos 是当前记录位置,一边写一边后移;checkpoint 是当前要擦除的位置,也是往后推移并循环的,擦除记录前要把记录更新到数据文件;write pos 和 checkpoint 之间的部分用来记录新的操作。如果 write pos 追上了 checkpoint 就需要停下先擦除一些记录,把 checkpoint 推进下
redo log 可以让 InnoDB 保证即使数据库发生异常重启,之前提交的记录也不会丢失,这个能力称为 crash-safe
bin log(归档日志)
bin log 是 MySQL 的 Server 层维护的一种二进制日志,主要是用来记录对mysql数据更新或潜在发生更新的SQL语句,并以"事务"的形式保存在磁盘中
redo log 和 binlog 的区别
- redo log 是 InnoDB 引擎特有的;binlog 是 Server 层实现的,所有引擎都可以用
- redo log 是物理日志,记录的是 “在某个数据页上做了什么修改”;binlog 是逻辑日志,记录的是语句的原始逻辑,例如:给 ID=2 这一行的 C 加 1
- redo log 是循环写的,空间固定会用完;binlog 是追加写的,文件写到一定大小,会切换到下一文件,不会覆盖
update 语句执行流程
update T set c=c+1 where ID=2;
- 执行器先查找引擎取 ID=2 这一行
- 执行器拿到引擎给的行数据,把这个值加上1,得到新的一行数据,再调用引擎接口写入这行新数据
- 引擎将这行新数据更新到内存中,同时将这个更新操作记录到 redo log 里面,此时,redo log 处于 prepare 状态,然后告知执行器执行完成,随时可以提交事务
- 执行器生成这个操作的 binlog ,并把 binlog 写入磁盘
- 执行器调用引擎的提交事务接口,引擎把刚刚写入的 redo log 改成 commit 状态,更新完成
两阶段提交
两阶段提交主要是为了保证 redo log 和 binlog 保持一致
假设当前 ID=2 的行,字段 c 为 0,语句写完第一个日志后,第二个日志还没写完期间发生了 crash:
- 先写 redo log 后写 binlog
由于 redo log 写完之后,系统即使 crash,仍可以恢复数据,这时 c=1。但由于 binlog 没有写完,之后需要使用这个 binlog 恢复临时库时,恢复出来的 c=0,与原库不同 - 先写 binlog 后写 redo log
由于 redo log 还没写完,系统恢复后 c=0,但 binlog 里已经记录了,之后用 binlog 恢复时,恢复出来的 c=1,与原库不同
redo log 和 binlog 都可以用于表示事务的提交状态,而两阶段提交就是让这两个状态保持逻辑上的一致
数据恢复
当需要恢复到指定的某一秒时,比如某天下午两点发现中午十二点有一次误删表,需要找回数据,那你可以这么做:
- 首先,找到最近的一次全量备份,如果你运气好,可能就是昨天晚上的一个备份,从这个备份恢复到临时库;
- 然后,从备份的时间点开始,将备份的 binlog 依次取出来,重放到中午误删表之前的那个时刻