mysql通过sql update_「MySQL」 - SQL更新语句执行流程

一、更新涉及log

与SELECT流程不同,UPDATE操作会涉及两个日志模块,分别是redo log和bin log。

A、redo log

如果每次UPDATE操作,都找到对应记录,然后更新写入磁盘,IO成本、查找成本都很高。为了解决这个问题,MySQL设计者使用了WAL(Write-Ahead Logging)技术,先写日志,再写磁盘。

当有一条记录需要更新时,InnoDB引擎会把记录写到redo log里,并更新内存,并认为此时更新完成;InnoDB会在适当时,将记录更新到磁盘。

但是redo log大小固定,配置为一组4个文件。write_pos是当前记录的位置,checkpoint是需要擦除的位置,擦除前将记录更新到数据文件。相当于一个循环队列,如果队列写满,需要先暂定,将checkpoint向前推荐一段空间,再进行写入。

有了redo log,InnoDB可以保证数据库发生异常重启,记录不丢失,称为crash-safe。

B、bin log

redo log是InnoDB存储引擎的日志,Server层的日志为bin log。redo log是循环写入,bin log是追加写入,不会覆盖之前的日志。

二、UPDATE流程

mysql> UPDATE T SET age = age+1 WHERE id = 1;执行器先找引擎找id=1这行记录。id为主键,引擎通过索引找到记录;

执行器拿到行记录,对age+1,调用引擎写接口,更新数据;

引擎将新记录更新到内存,并将更新记录写入redo log,redo log处于prepare状态,随时可以提交事务;

执行器生成bin log写入磁盘;

执行器调用引擎提交事务接口,把redo log成成commit状态,更新完成。

innodb_flush_log_at_trx_commit设置为1,表示每次事务的redo log都直接持久化到磁盘,可以保证MySQL异常重启之后数据不丢失。

sync_binlog设置为1,表示每次事务的bin log都持久化到磁盘,可以保证MySQL异常重启之后bin log不丢失。

三、二阶段提交

为了让两份日志逻辑一致,上述操作使用了二阶段提交。

假设不使用二阶段提交,会有如下两种情况。

假设age = 10,使用之前的UPDATE SQL。

A.先写redo log,后写bin log;中间发生崩溃,通过redo log自动恢复数据,age = 11。但是因为bin log没有写入,如果用之前的数据进行恢复,age = 10。

B.先写bin log,后写redo log;中间发生崩溃,age = 10(未更新),使用bin log恢复,age = 11。

都会出现数据不一致的情况,使用二阶段提交,让两份日志数据保持逻辑上的一致。

参考:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值