update语句在MySQL中是如何执⾏的
⼀、假设要执⾏的SQL语句如下
update users set name = 'aaa' where id = 5;
把users表中字段id等于5的数据⾏的name字段的值修改为aaa,那么这条SQL语句是如何执⾏的呢?
从应⽤服务器和MySQL服务器的⾓度看,⾸先是应⽤服务器中的⼀个业务模块需要更新数据库数据,先通过⼀个数据库连接将SQL语句发送到MySQL服务器上,然后经过SQL接⼝、解析器、优化器、执⾏器⼏个环节,解析SQL语句,⽣成执⾏计划,执⾏器根据这个执⾏计划去调⽤存储引擎的接⼝去执⾏语句。
⼆、在存储引擎中,这条更新语句是如何执⾏的
(存储引擎有很多种,此处只记录InnoDb存储引擎)
执⾏update users set name = 'aaa' where id = 5;
步骤说明:
⼀、将包含id=5的数据页加载进Buffer Pool中
Buffer Pool:是InnoDB存储引擎中⾮常重要的组件,就是⼀个缓冲池,会缓存⼀些从磁盘加载进来的数据页,在查询的时候,如果是缓冲池⾥已经加载的数据,就不需要去查磁盘⽂件了,查询内存的效率⽐查询磁盘⽂件的效率要⾼的多。对数据的增删改查其实都是基于buffer pool的。
所以在执⾏update语句的时候,⾸先是要先到id=5的这⾏数据,因此先在缓冲池⾥查,如果缓冲池中不存在的话,就会从磁盘⽂件加载到缓冲池。
⼆、将旧数据写⼊undo log⽇志⽂件
假设这条数据原本的值name=‘xx’,现在要修改为‘aaa’,这⾥要先把旧值‘xx’写⼊到undo⽇志⽂件中去。⽬的是为了事务的回滚和⽀持InnoDB的MVVC机制。
事务的回滚:InnoDB存储引擎是⽀持事务的,在事务提交前,是可以对修改了的数据进⾏回滚的,就是把更新的'aaa'值回滚成之前
的‘xxx’,所以为了回滚数据的需要,这⾥要记录旧值。
MVVC机制:多版本并发控制。是InnoDB存储引擎的⼀种处理并发读写的机制,其中redo log版本链是重要基础。这⾥先不赘述,后⾯记录到数据库的并发时再详细写。
三、更新Buffer Pool中的缓存数据
在第⼀步中已经把id=5的这⾏数据加载到Buffer Pool中了,这个时候这⾏数据的name字段值还是‘xx’,要将其修改为新值‘aaa’。
此时,这⾏数据就成了脏数据,即这个时候,在Buffer Pool中的数据与在磁盘的数据是不⼀致的,磁盘的数据还是旧的‘xx’。
四、写redo log buffer
redo log buffer:是内存中的⼀个缓冲区,记录的是你对这⾏数据的操作。此时在redo log buffer中记录,对id=5的这⾏数据修改了name字段的值为‘aaa’。
sql中update什么意思redo log buffer是⽤来在MySQL突然宕机的时候,⽤来恢复更新过的数据的。因为若MySQL数据库宕机,Buffer Pool中缓存的数据会丢失,此时磁盘⽂件还未更新,那么之前的修改就丢失了。此时只需要重新执⾏redo log buffer中记录过的操作,就可以恢复出宕机前的Buffer Pool。
但是redo log buffer也是在InnoDb存储引擎内存中的,若MySQL宕机,则redo log buffer数据也是会丢失的,因此redo log buffer这个记录是要进⾏持久化的,继续看下⼀步。
五、提交事务的时候将redo log⽇志写⼊os cache或者磁盘
为什么是提交事务的时候写⽽不是其它的时候呢?假设这条update操作的事务还未提交,此时MySQL宕机了,会怎么样?
Buffer Pool缓冲池的数据丢失,同时redo log buffer中记录的操作也会丢失,但是此时数据丢失并不重要,因为事务还未提交,没提交的事务就代表没执⾏成功,磁盘上的数据还是原来旧的数据‘xx’,此时不会有任何影响。
如果事务提交了,就表⽰这个执⾏成功了。事务有四⼤特性,ACID,即原⼦性、⼀致性、隔离性和持久性。其中持久性就是说,⼀旦事务提交,则其所做的修改就要永久保存到数据库中,此时即使系统崩溃,修改过的数据也不会丢失。
如果要事务提交,则应该将redo⽇志从redo log buffer中刷⼊到磁盘⽂件⾥。
这⾥InnoDB提供了⼏种策略,这个策略是通过参数 innodb_flush_log_at_trx_commit来配置的。
值为0,表⽰提交事务的时候,不会把redo log buffer⾥的数据刷⼊到磁盘⽂件中。此时可能事务提交成功,但是MySQL宕机,导致内存中的数据和redo⽇志都丢失了。这是不符合事务的持久性的。
值为1,表⽰提交事务的时候,把redo log从内存刷⼊到数据库的磁盘⽂件中去。此时只要事务提交成功,那么redo log就必然在磁盘⽂件⾥了,这个数据的修改也是不会丢失的。哪怕此时MySQL系统宕
机,Buffer Pool中的数据还未刷新到磁盘中,磁盘中还是修改前的旧值‘xx’,只要MySQL重启,就可以根据redo⽇志⽂件去恢复之前做过的修改,重做⼀次redo buffer,然后在合适的时机将脏数据刷回磁盘⽂件。
值为2,表⽰提交事务的时候,把redo log buffer中的数据写⼊磁盘⽂件对应的os cache缓存⾥去,⽽不是直接写⼊磁盘⽂件,可能1秒后才会把os cache⾥的数据写⼊磁盘⽂件。os cache是系统缓存,这种情况下,如果MySQL服务器宕机,则数据不会丢失,但是如果机器宕机,那么os cache的数据就会丢失了,因此同样会导致数据丢失。
这三种redo⽇志刷盘策略根据系统的特点和需要进⾏选择,⼀般是设置为1,即提交事务的时候,redo⽇志必须刷⼊到磁盘⽂件⾥,这样可以严格的保证,提交事务之后,数据绝对不会丢失,因为有redo ⽇志在磁盘⽂件⾥可以恢复出buffer pool。
六、将Buffer Pool缓冲池中的数据刷回磁盘
数据库中的数据最终都是要存放到磁盘⽂件中去的,但是为了执⾏效率,在执⾏SQL语句的时候,是不可能直接将数据的修改写⼊磁盘⽂件的,因此才有了redo⽇志。
使⽤redo ⽇志,存储引擎在修改数据的时候,只需要修改这⾏数据在Buffer Pool中的值,即这个数据
的内存拷贝,然后将这个⾏为记录到redo⽇志⽂件中,记录redo⽇志是采⽤追加的⽅式,即在磁盘上⼀⼩块区域内的顺序IO,这个操作是很快的。
⽽真实的数据在数据库磁盘⽂件中,分布磁盘中不同的位置,在写数据的时候,磁头需要在磁盘的多个位置移动,属于随机IO,这个过程⽐顺序IO效率低很多,速度相当慢,随便⼀个⼤磁盘⽂件的随机读写操作都可能要⼏百毫秒。
因此,会有⼀个IO线程在后台运⾏,在数据库空闲的时候或者Buffer Pool缓冲页回收的时候,将数据慢慢写回到数据库磁盘⽂件中去。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论