mysql> create table T(id int primary key,c int);
mysql> update T set c=c+1 where id=2;
大体流程与查询流程是一样的:先是检查连接权限,然后经过分析器,知道是更行语句,查询缓冲遇到更行语句就清空该表的查询缓存;优化器决定使用id这个索引并生成执行计划;执行器负责执行,找到这一行,并进行更行。
与查询流程不一样的是:更新流程还涉及两个重要的日志模块:redo log与binlog(归档日志)
………………………………………………………………………………………………………………………………………………
Redo log
一个店家有两个账本,A一个记录了所有的客户消费信息与欠账信息;
可日常繁忙时,无法快速定位将客人信息记录到A中,这时就需要临时有一个B,随时记录客人消费信息;等晚上客人走了,再将B中的信息整理到A中;
B账本就是redo log
……………………………………………………………………………………………………………………………………………………
Mysql里也有这个问题,如果每一次的更行操作都需要写入磁盘,然后磁盘也要找到对应的那条记录,然后再更行,整个过程IO成本,查找成本会很高。
Mysql就找到一种解决方法:就是WAL技术:先写日志,再写磁盘。
具体来说:当有一条记录需要更新的时候,INNODB引擎就会把记录写到redo log,并更行内存,这个时候更新就算完成了;同时,innodb引擎会在适当的时候,将这个操作记录更新到磁盘里面。
……………………………………………………………………………………………………………………………………
店铺掌柜,发现B账本快写满了,那么他就会将已经写进A账本的记录擦掉,就有了剩余空间,继续往里面写记录
……………………………………………………………………………………………………………………………………
write pos 是当前记录的位置,一边写一边后移,写到第 3 号文件末尾后就回到 0 号文件开头。checkpoint 是当前要擦除的位置,也是往后推移并且循环的,擦除记录前要把记录更新到数据文件。
如果wiite pos 追上了checkpoint,表示redo已经满了,不能继续执行更行操作了,要停下来,等checkpoint向前推移,有了剩余空间,再继续更新
…………………………………………………………………………………………………………………………………………
有了redo log,innodb就可以保证数据库发生异常重启后,之前提交的记录都不会丢失,这个能力称为crash-safe
Redolog 不是记录数据页“更改之后的状态”,而是记住“页做了什么改动”
Binlog有两种模式,statement格式记录sql语句;row格式记录行内容:更行前后都有
一般选用row模式,因为遇到主从不一致时,row模式,更改前后都有,恢复之后,不会丢失某个事务的数据。
两种日志的不同:
这两种日志有以下三点不同。
1 redo log 是 InnoDB 引擎特有的;binlog 是 MySQL 的 Server 层实现的,所有引擎都可以使用。
2 redo log 是物理日志,记录的是“在某个数据页上做了什么修改”;binlog 是逻辑日志,记录的是这个语句的原始逻辑,比如“给 ID=2 这一行的 c 字段加 1 ”。
3 redo log 是循环写的,空间固定会用完;binlog 是可以追加写入的。“追加写”是指 binlog 文件写到一定大小后会切换到下一个,并不会覆盖以前的日志。
……………………………………………………………………………………………………………………………………………………
Binlog或redolog可以二选一吗?
首先,redo log只有innodb引擎才有,所以不能丢;redo log不具备归档的功能,刷到磁盘后就被清除了;而binlog是追加,可以归档,用作数据库恢复,数据库扩容都很重要。
……………………………………………………………………………………………………………………………………………………
执行器先找引擎取ID=2,ID是主键,引擎通过索引快速找到ID=2这一行;如果这一行本就在内存中,就直接返回给执行器;否则需要从磁盘读入内存,然后再返回。
执行器拿到引擎给的行数据,把这个值加1,得到新的行数据,再调用引擎接口写入这行新数据。
引擎将这行数据更新到内存中,同时将这个更行操作记录到redo log中,此时redo log处于prepare状态。然后告知执行器执行完成了,随时可以提交事务。
执行器生成这个操作的binlog,并把binlog写入磁盘。
执行器调用引擎接口,引擎把redo log 改成commit状态,更新完成。
最后三步看上去有点绕,将redo log写入拆分为两个步骤:prepart和commit------两阶段提交。
…………………………………………………………………………………………………………………………………………
内容主体来自林晓斌老师《mysql实战45讲》