当前位置: 首页 > 后端技术 > PHP

【大厂专访04】如何执行一条MySQL更新语句?

时间:2023-03-30 02:01:27 PHP

本文已收录到1.1K星号开源学习指南——《大厂面试指北》,想了解更多大厂访谈内容,获取《大厂面试指北》离线PDF版,请扫一扫下方二维码关注“大厂访谈”,谢谢大家!《大厂面试指北》项目地址:https://github.com/NotFound9/interviewGuide《大厂面试指北》项目截图:获取《大厂面试指北》离线PDF版,请扫描下方二维码关注公众号《大厂访谈》这是在线的我找了一张流程图,写的不错。大家可以先看图,再详细阅读下面的步骤。执行过程:1.连接验证与分析客户端与MySQLServer建立连接,向MySQLServer发送一条语句,收到后为这条语句创建解析树,然后进行优化,(解析器知道语句是什么执行时,它会评估使用各种索引的成本,然后使用索引,调整表的连接顺序)然后调用innodb引擎的接口来执行语句。2.写undologinnodb引擎先启动事务,对旧数据生成UPDATE语句(如果是INSERT会生成UPDATE语句),用于提交失败后回滚,写undolog,获取回滚指针,更新数据行的回滚指针和版本号(会被设置为更新后的事务id)。3.从索引中查找数据根据查询条件在B+树中查找这一行数据(如果是唯一索引就可以找到第一条数据(因为有唯一约束),如果是普通索引,全部找到数据。)4.更新数据,首先判断数据页是否在内存中?4.1如果数据页在内存中,首先判断更新的索引是普通索引还是唯一索引?4.1.1普通索引如果更新索引是普通索引,直接更新内存中的数据页4.1.2唯一索引如果更新索引是唯一索引,判断更新是否会破坏数据的唯一性,如果不是,然后更新内存中的数据页。4.2如果数据页不在内存中,首先判断更新的索引是普通索引还是唯一索引?4.2.1普通索引如果被更新的索引是普通索引,数据页的更新操作会被记录在changebuffer中,changebuffer空闲时会异步更新到磁盘。4.2.2唯一索引如果更新的索引是唯一索引,因为需要保证更新后的唯一性,不能延迟更新。数据页必须从磁盘加载到内存,然后判断更新后是否会发生数据冲突。如果是这样,请更新数据页。5.写入undolog(prepare状态)将数据页的变化写入redolog,设置redolog为prepare状态。6、写入binlog(commit状态),提交事务通知MySQL服务器更新操作已经写入redolog,可以随时提交,将执行的SQL写入binlog日志,更改redologcommit状态,提交交易成功。(判断事务是否成功的依据是是否成功写入binlog,写入成功后,即使MySQLServercrash,恢复时也会根据binlog和redolog恢复。对于详情请看下面的崩溃恢复原理)补充资料:什么是两阶段提交系统?更新时,先改变内存中的数据页,将更新操作写入重做日志。此时redolog进入prepare状态,然后通知MySQLServer执行完成,可以随时提交。MySQLServer将更新后的SQL写入binlog。然后调用innodb接口设置redolog为已提交状态,更新完成。如果只是写binlog提交,突然出现故障,master节点可以根据redolog将数据恢复到最新,但是这部分更新的数据在主从同步时会丢失。如果只是写binlog,然后写redolog,如果突然出现故障,master节点根据redolog恢复数据时,会丢失这部分数据。MySQL崩溃后,事务恢复的判断规则是什么?(根据redolog是否commit或binlog是否complete来判断)如果redolog中的transaction是complete,即已经有commit标志,则直接提交;如果redolog中的transaction只有completeprepare,则判断对应的transactionbinlog是否存在且是否complete:a.如果是,提交事务;b.否则,回滚事务。什么是撤销日志?undolog主要是保证事务的原子性。如果事务执行失败,则回滚。用于事务执行失败后回滚数据。undolog是记录SQL的逻辑日志。(可以认为当一条记录被删除时,undolog中会记录一条对应的insert记录,反之,当一条记录被更新时,会记录一条对应的update记录。)事务提交后,undolog并不会立即删除,而是放在一个待删除的链表中。有一个purge线程判断是否有其他事务使用上一个事务之前的版本信息,然后决定是否可以清理。简单的说就是之前的事务已经提交成功了,这些undo可以删除。什么是changebuffer(即更新数据页的操作被缓存)。更新数据时,如果数据行所在的数据页在内存中,则直接更新内存中的数据页。如果不在内存中,innodb会将这些更新操作缓存在changebuffer中,以减少磁盘IO次数。当下次查询需要访问数据页时,会执行changebuffer中的操作,更新数据页。适用于写多读少的场景,因为即使立即写入,也不太可能被访问到。延迟更新可以减少磁盘I/O。只会用到普通索引,因为更新唯一性索引的时候需要判断唯一性,所以没有必要。什么是重做日志?重做日志是为了保证事务的持久性。因为changebuffer是保存在内存中的,如果机器重启后changebuffer中的变化没有及时更新到磁盘,就需要根据redolog来检索这些更新。好处是减少了磁盘I/O的次数,即使发生故障也可以根据redolog将数据恢复到最新状态。缺点是会在内存中造成脏页,后台线程会自动刷脏页,或者在数据页被淘汰时刷盘。此时收到的查询请求需要等待,影响查询。参考资料:https://gsmtoday.github.io/20...https://www.infoq.cn/article/...精彩回顾:【大厂专访01】高并发场景下如何保证缓存与数据库?【大厂访谈02】如何清理Redis的过期key?【大厂访谈03】MySQL如何解决幻读问题?【大厂专访04】如何执行一条MySQL更新语句?【大厂访谈05】谈谈你对MySQL中锁的理解?【大厂专访06】谈谈你对Redis持久化的理解?【大厂专访第07期】谈谈你对同步锁的理解?【大厂专访08】谈谈你对HashMap的理解?