执行一条select语句要经过的步骤
- 连接器
- 与客户端进行TCP三次握手进行连接
- 查询缓存
- MySQL8.0以后就将这部分给删掉了
- 解析SQL
- 词法分析(分析出Token和KeyWard(select和from等))
- 语法分析根据语法规则判断出MySQL语句如果没问题会构建出SQL语法树,如果语法不对会报错(from写成form)
- 但是表不存在或字段不存在不是在这检测出的
- 执行SQL
- 预处理
- 在这个阶段会检测出表不存在或者字段不存在等错误
- 优化器
- 如果查询时可以选择多个索引,那优化器会基于成本考虑去选择一个合适的执行方案
- 执行器
- 按照优化器选择的执行方案去执行SQL语句,从存储引擎读取记录返回给客户端
- 预处理

执行一条update语句
执行update的操作也会发生执行select的操作,但是新增了
- 去buffer Pool读取数据
- 如果读取到,直接返回个执行器
- 没读到,去磁盘中读入数据到buffer Pool中
- 比对更新前后的数据
- 如果相同那就不进行更新流程
- 不同的话那就把更新前的数据和更新后的数据都传给InnoDB层,让InnoDB层执行更新
- 开启事务,首先记录相应的undo log,把被更新的列的旧值记录下来,生成undo log语句,写入buffer pool的undo界面,后续的undo log更改都需要记录到redo log buffer里
- 开启更新,先更新内存(标记为脏页),再把记录写到redo log buffer里,这个时候更新就完成了。后续会选择一个合适的时机进行脏页刷盘,刷盘时会先刷redo log buffer里的数据再刷脏页的数据。
- 一条更新语句执行完后,此时记录的binlog会保存到binlog cache里并没有刷新到硬盘上的binlog文件里,在事务提交时才会将所有的binlog刷新到硬盘。
- 事务提交
- prepare:将redo log状态设为prepare,并将redo log刷新到硬盘里(这个redo log写入磁盘的是数据的变更情况)
- commit:将binlog刷新到磁盘,接着将redo log状态设置为commit(这个redo log写入磁盘的是事务的状态标记prepare -> commit)
- undo log:InnoDB存储引擎层的逻辑日志,保证了事务的原子性,用于事务回滚和MVCC
- redo log:InnoDB存储引擎层的物理日志,保证了事务的持久性,用于掉电等故障的数据恢复
- bin log:Server层的逻辑日志,用于主从复制和数据备份
逻辑日志和物理日志的区别
- 逻辑日志:描述的逻辑操作,记录的逻辑语句,恢复的时候需要重放逻辑。结构紧凑。
- 物理日志:记录的数据的变化例如 对 XXX 表空间中的 YYY 数据页 ZZZ 偏移量的地方做了AAA 更新,占用的空间较大,但是数据恢复的速度快
Redo log
包含两部分一部分是InnoDB存储引擎层的redo log buffer另一部分是磁盘里的redo log file
- 让事务有了持久性,让MySQL有了崩溃恢复的能力能够保证MySQL在任何时间崩溃,都能够恢复已提交的数据
- WAL实现了让随机写变成了顺序写(写入redo log是顺序写),提高了IO的效率
- 具体实现:写操作不立刻写到磁盘上,而是先写到日志上,然后再在合适的时间写到磁盘上
- undo log页面被修改后要把修改列的旧值写入buffer Pool里的undo页面,同时也要把相关的语句写入redo log里进行持久化存储
undo log
- 让事务有了原子性
- 能够实现MVCC
bin log
- 数据恢复和主从复制
redo log 和 undo log 的使用场景
- 事务提交之前发生崩溃(不是宕机崩溃而是事务出现问题)重启后会根据undo log回滚事务。
- 事务提交之后发生崩溃(宕机崩溃)重启后根据redo log恢复事务,不会造成数据丢失。
redo log和bin log的使用场景
- redo log文件是循环写,边写边擦,只记录未被刷入磁盘的物理地址,已经刷入磁盘的数据会从redo log中擦除。redo log是存储引擎层的日志能够知道脏页刷没刷盘,从而在崩溃恢复的时候恢复那些没被刷盘的脏页数据。
- binlog 保存的全量的日志,保存了所有数据的变更,只要记录在binlog上的数据都可以恢复,binlog是server层的日志不能知道哪写脏页还没有刷盘。
binlog 两阶段提交过程(为了redo log和binlog的日志一致性,开启了内部XA事务)
- prepare阶段:将XID写入redo log里,redo log刷入磁盘
- commit阶段:将XID写入binlog里,binlog刷入磁盘,将redo log状态设置为commit

两个日志出现数据不一致的节点
- 当MySQL重启的时候会按顺序扫描redo log找到XID后会拿着XID去binlog里去找
- redo log刷入了磁盘,而还没有将XID写入binlog里。
- 这个时候redo log里有XID完成了刷盘而binlog里没有XID,发生了数据不一致,进行回滚事务。
- binlog刷入磁盘,binlog的状态还没设置为commit。
- 这个时候redo log里有XID完成刷盘并且binlog里也有XID完成刷盘,进行事务提交。
- 所以对于处于prepare状态的redo log来说既可以进行提交事务也可以进行回滚事务,主要取决于binlog里有没有XID,也就是binlog的写成功为事务成功的标识。
- redo log刷入了磁盘,而还没有将XID写入binlog里。