MySQL笔记(2):一条SQL更新的执行
自存笔记,学习MySQL实战45讲
第二讲:一条SQL更新语句是如何执行的
查询语句需要走的流程,更新语句也同样需要,比如连接器验证链接身份、解析器解析词法语法等,唯一不同在于执行器执行的时候,特殊的更新操作。而这个操作又涉及到两个日志:redolog(重做)和binlog(归档)
如果更新操作不借助日志?
- 方案一:每次更新直接写入磁盘,这样每次更新都对应一次磁盘io,成本过高
- 方案二:每次修改把脏页暂存在内存里,然后延迟异步刷盘(保证性能)。但如果系统突然崩溃,内存中的脏页会丢失,此时无法保证事务的持久性
脏页:内存中已经被修改但还没被刷新到磁盘上的数据库页面
显然,这两种方法都是有缺陷的,既要保证性能,又要保证持久性,就引入了WAL技术,也就是Write-Ahead Logging,关键点是先写日志,再写磁盘,这个日志就是redolog
RedoLog日志
- InnoDB引入的一块磁盘区域,在事务提交时,把日志写入这块磁盘区域,记录下对数据页的物理修改
- 这样一来,即使数据库发生异常重启,也可以凭借RedoLog来找回脏页数据,这个能力叫crash-safe
- RedoLog是固定大小的文件,以循环的方式写入,不断覆盖最早的内容
binlog日志
MySQL整体来看有两块,Server层用来实现MySQL大部分功能,存储引擎层用来存储数据。RedoLog是InnoDB引擎独有的日志。Server层也有自己的日志,叫binlog(归档日志)
- binlog是记录所有数据库表结构变更和表数据修改的二进制日志
- 由Server层实现,所有引擎都可以使用
- binlog是可以追加写入的,当binlog文件写到一定大小后会切换下一个,并不会覆盖以前的日志
执行update语句的内部流程
1 | mysql> update T set c=c+1 where ID=2; |
- 执行器先找引擎取 ID=2 这一行。ID 是主键,引擎直接用树搜索找到这一行。如果 ID=2 这一行所在的数据页本来就在内存中,就直接返回给执行器;否则,需要先从磁盘读入内存,然后再返回
- 执行器拿到引擎给的行数据,把这个值加上 1,比如原来是 N,现在就是 N+1,得到新的一行数据,再调用引擎接口写入这行新数据
- 引擎将这行新数据更新到内存中,同时将这个更新操作记录到 redo log 里面,此时 redo log 处于 prepare 状态。然后告知执行器执行完成了,随时可以提交事务
- 执行器生成这个操作的 binlog,并把 binlog 写入磁盘
- 执行器调用引擎的提交事务接口,引擎把刚刚写入的 redo log 改成提交(commit)状态,更新完成。
两阶段提交
指的是把redolog的写入分成了两个步骤,prepare和commit,这就是两阶段提交。
记住,如果不使用“两阶段提交”,那么数据库的状态就有可能和用它的日志恢复出来的库的状态不一致
思考题
定期全量备份的周期,在什么场景下,一天一备会比一周一备更有优势?
- 数据更新频繁的系统,如电商、银行
- 数据一致性要求高的系统,如证券交易系统
All articles on this blog are licensed under CC BY-NC-SA 4.0 unless otherwise stated.