共计 2273 个字符,预计需要花费 6 分钟才能阅读完成。
作者:NotFound9
链接:
https://www.cnblogs.com/notfo…
这是在网上找到的一张流程图,写的比较好,大家可以先看图,然后看详细阅读下面的各个步骤。
执行流程:
1. 连接验证及解析
客户端与 MySQL Server 建立连接,发送语句给 MySQL Server,接收到后会针对这条语句创建一个解析树,然后进行优化,(解析器知道语句是要执行什么,会评估使用各种索引的代价,然后去使用索引,以及调节表的连接顺序)然后调用 innodb 引擎的接口来执行语句。
2. 写 undo log
innodb 引擎首先开启事务,对旧数据生成一个 UPDATE 的语句 (如果是 INSERT 会生成 UPDATE 语句),用于提交失败后回滚,写入 undo log,得到回滚指针,并且更新这个数据行的回滚指针和版本号 (会设置为更新的事务 id)。
3. 从索引中查找数据
根据查询条件去 B + 树中找到这一行数据(如果是唯一性索引,查到第一个数据就可以了(因为有唯一性约束),如果是普通索引,会把所有数据查找出来。)
4. 更新数据
首先判断数据页是否在内存中?
4.1 如果数据页在内存中
先判断更新的索引是普通索引还是唯一性索引?
4.1.1 普通索引
如果更新的索引是普通索引,直接更新内存中的数据页
4.1.2 唯一性索引
如果更新的索引是唯一性索引,判断更新后是否会破坏数据的唯一性,不会的话就更新内存中的数据页。
4.2 如果数据页不在内存中
先判断更新的索引是普通索引还是唯一性索引?
4.2.1 普通索引
如果是更新的索引是普通索引,将对数据页的更新操作记录到 change buffer,change buffer 会在空闲时异步更新到磁盘。
4.2.2 唯一性索引
如果是更新的索引是唯一性索引,因为需要保证更新后的唯一性,所以不能延迟更新,必须把数据页从磁盘加载到内存,然后判断更新后是否会数据冲突,不会的话就更新数据页。
5. 写 undo log(prepare 状态)
将对数据页的更改写入到 redo log,将 redo log 设置为 prepare 状态。
6. 写 bin log(commit 状态),提交事务
通知 MySQL server 已经更新操作写入到 redo log 了,随时可以提交,将执行的 SQL 写入到 bin log 日志,将 redo log 改成 commit 状态,事务提交成功。(一个事务是否执行成功的判断依据是是否在 bin log 中写入成功。写入成功后,即便 MySQL Server 崩溃,之后恢复时也会根据 bin log,redo log 进行恢复。具体可以看看下面的崩溃恢复原则)
补充资料:
二段提交制是什么?
更新时,先改内存中的数据页,将更新操作写入 redo log 日志,此时 redo log 进入 prepare 状态,然后通知 MySQL Server 执行完了,随时可以提交,MySQL Server 将更新的 SQL 写入 bin log,然后调用 innodb 接口将 redo log 设置为提交状态,更新完成。如果只是写了 bin log 就提交,那么忽然发生故障,主节点可以根据 redo log 恢复数据到最新,但是主从同步时会丢掉这部分更新的数据。如果只是写 binlog,然后写 redo log,如果忽然发生故障,主节点根据 redo log 恢复数据时就会丢掉这部分数据。MySQL 崩溃后,事务恢复时的判断规则是怎么样的?(以 redolog 是否 commit 或者 binlog 是否完整来确定)如果 redo log 里面的事务是完整的,也就是已经有了 commit 标识,则直接提交;
如果 redo log 里面的事务只有完整的 prepare,则判断对应的事务 binlog 是否存在并完整:a. 如果是,则提交事务;b. 否则,回滚事务。
undo log 是什么?
undo log 主要是保证事务的原子性,事务执行失败就回滚,用于在事务执行失败后,对数据回滚。undo log 是逻辑日志,记录的是 SQL。(可以认为当 delete 一条记录时,undo log 中会记录一条对应的 insert 记录,反之亦然,当 update 一条记录时,它记录一条对应相反的 update 记录。)在事务提交后,undo log 日志不会立即删除,会放到一个待删除的链表中,有 purge 线程判断是否有其他事务在使用上一个事务之前的版本信息,然后决定是否可以清理,简单的来说就是前面的事务都提交成功了,这些 undo 才能删除。change buffer 是什么(就是将更新数据页的操作缓存下来)在更新数据时,如果数据行所在的数据页在内存中,直接更新内存中的数据页。如果不在内存中,为了减少磁盘 IO 的次数,innodb 会将这些更新操作缓存在 change buffer 中,在下一次查询时需要访问这个数据页时,在执行 change buffer 中的操作对数据页进行更新。适合写多读少的场景,因为这样即便立即写了,也不太可能会被访问到,延迟更新可以减少磁盘 I /O,只有普通索引会用到,因为唯一性索引,在更新时就需要判断唯一性,所以没有必要。
redo log 是什么?
redo log 就是为了保证事务的持久性。因为 change buffer 是存在内存中的,万一机器重启,change buffer 中的更改没有来得及更新到磁盘,就需要根据 redo log 来找回这些更新。优点是减少磁盘 I / O 次数,即便发生故障也可以根据 redo log 来将数据恢复到最新状态。缺点是会造成内存脏页,后台线程会自动对脏页刷盘,或者是淘汰数据页时刷盘,此时收到的查询请求需要等待,影响查询。
如有错误或其它问题,欢迎小伙伴留言评论、指正。如有帮助,欢迎点赞 + 转发分享。
欢迎大家关注民工哥的公众号: 民工哥技术之路