上一章我们讲了一条SQL是如何做查询的,其中经历了许多步骤。这次来讲讲一条SQL是如何做更新操作的。
常有大佬说他可以把MySQL恢复到半个月内任意一秒的状态,今天也来谈谈这是如何做到的呢?
之前我们讲到了一条SQL的执行要经过连接器、查询缓存、分析器、优化器、执行器,最后到达存储引擎。其实更新语句也会同查询语句一样,把这些路都走一篇。不过会在此基础上更多一些步骤。还是以一条SQL为例子:
创建一个表T
mysql> create table T(ID int primary key, c int);
如果想把ID=10这行的值+1,SQL就是这样:
mysql> update T set c=c+1 where ID=10;
先通过连接器连接数据库。如果查询缓存中有值就取,没有就走下一步。,分析器会通过词法和语法解析知道这是一条更新语句。优化器决定要使用 ID 这个索引。然后,执行器负责具体执行,找到这一行,然后更新。
与查询流程不一样的是,更新流程还涉及两个重要的日志模块,它们正是我们今天要讨论的主角:redo log(重做日志)和 binlog(归档日志)。
设想一下,如果每一次的更新操作都需要写进磁盘,然后磁盘也要找到对应的那条记录,然后再更新,整个过程 IO 成本、查找成本都很高。那么MySQL是如何解决这个问题的呢?
这就不得不提到MySQL里常说的WAL技术。全称是 Write-Ahead Logging,它的关键点就是先写日志,再写磁盘,也就是先写把那些SQL都记录下来,等统一时间再来写入。
具体来说,当有一条记录要更新的时候,InnoDB引擎会把这条记录先写到redo log里,并更新内存,再等到系统比较空闲的时候把这个操作记录更新到磁盘。如果一直都很忙没有空闲,那么redo log就会先写入一部分,为后面留下空间。(InnoDB的redo log是固定大小的。比如可以配置为一组 4 个文件,每个文件的大小是 1GB,那么总共就可以记录 4GB 的操作,每次更新一部分到磁盘就可以把已更新的内容擦除)。
有了 redo log,InnoDB 就可以保证即使数据库发生异常重启,之前提交的记录都不会丢失,这个能力称为 crash-safe。也就是就算异常重启也能找到写在redo log中的SQL执行内容了。
redo log是InnoDB引擎特有的日志。Sever层也有自己的日志,binlog(归档日志)。
这两种日志有以下三点不同。
那么我们回头来看看上面的SQL在MySQL里是怎么执行的:
看完你可能会问,写入redo log后这个prepare是啥意思,还有写完binlog又要commit提交事务。这里的prepare和commit就是将redo log拆成了两阶段提交。
为什么必须有“两阶段提交”呢?这是为了让两份日志之间的逻辑一致。由于 redo log 和 binlog 是两个独立的逻辑,如果不用两阶段提交,要么就是先写完 redo log 再写 binlog,或者采用反过来的顺序。还是以前面的SQL举例。
1.如果先写redo log后写binlog,结果服务器故障了。redo log写完后c的值就已经+1了,但是由于binlog还没有写完就挂了,之后备份恢复的时候,binlog语句丢失,恢复的值还会是0。
2.如果先写binlog后写redo log。由于binlog写完之后挂了,redo log还没写,服务器恢复后发现事务无效,这个值还是0。但是binlog中已经记录了c从0变成1的日志。最后用binlog恢复的时候就会成为1,和原来库中的不同。
简单说,redo log 和 binlog 都可以用于表示事务的提交状态,而两阶段提交就是让这两个状态保持逻辑上的一致。
MySQL的日志系统在确保数据完整性、持久性和恢复能力方面起着关键作用。
数据一致性:通过重做日志和撤销日志,即使在系统故障的情况下,也能保证数据的一致性。当系统重启时,可以使用重做日志来恢复未完成的事务。
复制和备份:二进制日志用于主从复制和数据备份。从服务器可以读取主服务器的二进制日志,以保持与主服务器相同的数据状态。这使得实现高可用性和负载均衡变得容易。
慢查询监控:查询日志和慢查询日志可以帮助我们识别和优化性能问题。通过分析这些日志,可以找到需要优化的SQL语句或配置。
审计:查询日志可以用于审计目的,跟踪对数据库的访问和修改操作。这对于安全性和合规性检查非常有用。
补充:
MySQL的日志:
二进制日志(Binary Log):记录了对数据库执行的所有修改操作,以二进制形式存储。主要用于复制和数据恢复。
重做日志(Redo Log):存在于InnoDB存储引擎中,用于保证事务的持久性。
撤销日志(Undo Log):也存在于InnoDB存储引擎中,用于支持事务的回滚操作和多版本并发控制。
查询日志(General Query Log)和慢查询日志(Slow Query Log):用于记录数据库的活动和慢查询。