当前位置: 首页 > 科技观察

通过一条语句的执行,我们可以深入了解InnoDB

时间:2023-03-22 12:21:18 科技观察

MySQL最常用的存储引擎innodb的底层架构。今天,我们将通过一条update语句的执行来了解innodb是如何处理的,深入了解它的架构。假设更新语句是这样的:updateusersetname='xxx'whereid=1;这条SQL语句发送到MySQL后,会经过SQL接口、解析器、优化器、执行器几个阶段来解析SQL,生成执行计划。然后执行器调用存储引擎执行执行计划。如下图所示:图1MySQL底层架构接下来,我们将按照一条update语句来分析innodb存储引擎的架构设计。1、innodb最重要的组件:缓冲池(BufferPool)innodb存储引擎中有一个非常重要的组件,就是缓冲池(BufferPool),它会缓冲很多数据,这样在操作数据的时候以后可以直接操作内存。无需访问磁盘。图2InnoDB的重要组成缓冲池当innoDB执行上面的update语句时,会先检查id=1的语句是否在缓冲池中。如果没有,则需要从磁盘加载到缓冲池中,同时也会给这条记录加一个排它锁。后面会讲解锁相关的知识点。这不是重点,就不展开了。2.undologfile接下来准备更新id=1的数据时,id=1和name的原始值会被写入undolog文件。这样做的目的是什么?回滚当然方便。MySQL在事务中添加、删除和修改数据。如果事务提交失败,可以根据undolog回滚。图3undolog文件将id=1的待更新数据加载到bufferpool中,将待更新数据的旧值写入undolog文件后,即可更新记录。更新时,先更新缓冲池中的数据。更新后,缓冲池中的数据变为:name='xxx',磁盘上的数据仍然是name='zhangsan'。此时innoDB的数据状态变成了这样:图4更新缓冲池数据3.重做日志文件此时缓冲池和磁盘中的数据不一致。MySQL宕机了怎么办?这时候MySQL宕机了,缓冲池中的数据肯定会丢失。这时候就需要引入一个新的组件:redolog。redolog也是一个内存缓冲区,用来存放redolog,redolog用来记录你对数据所做的修改。比如对于id=1的记录,修改name,redolog可能是这样的:id=1,name='xxx'。图5redolog有了redolog,更新后的数据可以在mysql关机后重新启动恢复。但是如果此时MySQL数据库宕机了怎么办?一定是bufferpool中修改的数据,redologbufferlog会丢失。不过没关系,因为你更新数据的事务还没有提交,此时MySQL宕机了,事务会执行失败,客户端会收到数据库异常,磁盘上的数据会保留MySQL重启后也是如此。所以数据还是一致的。另外,重做日志是innoDB独有的组件。4.提交事务以上步骤完成后,就会提交事务,此时redolog会刷到磁盘。磁盘刷新策略可以通过innodb_flush_log_at_trx_commit配置。这个配置有几个选项:0,事务提交时,redolog不会刷到磁盘;1、默认值,当事务提交时,redolog会被刷到磁盘,只要事务提交成功,redolog就会进磁盘了。2.当提交一个事务时,redo会被刷新到os缓存中。操作系统偶尔会将os缓存中的数据刷新到磁盘中。因此,当innodb_flush_log_at_trx_commit等于0或2时,redolog中的所有事务都被成功提交,没有写入磁盘的可能,缓冲池中更新的数据也丢失了。此时MySQL重启时,更新后的数据无法根据redo恢复,会出现数据不一致的情况。所以一般情况下,我们会配置innodb_flush_log_at_trx_commit为1。图6redolog5.Binlog日志其实在MySQL中提交一个事务的时候,也会记录binlog。binlog是MySQL服务器本身的日志文件。重做日志属于一种偏向于物理性质的重做日志,里面记录的内容相当于“对某个数据页的某条记录进行了某项修改”。Binlog称为归档日志,记录的是偏逻辑的日志,类似于redis的aof日志。我们在提交东西的时候,除了将redolog写入磁盘外,还会同时将相应的binlog写入磁盘文件。图7binlog日志和redolog日志是一样的。binlog日志有两种刷新策略,对应的配置项为:sync_binlog。0,默认值,当事务提交时,binlog会被flush到os缓存中。1.提交事务时,binlog会写入磁盘。所以当sync_binlog设置为0时,如果机器宕机,binlog可能会丢失。设置为1时,binlog日志即使宕机也不会丢失。当我们将binlog日志写入磁盘后,再完成最后的事务提交,最后将本次更新对应的binlog日志文件名和本次更新的binlog日志在文件中的位置写入到redolog日志中同时,在redolog日志文件中写入commitmark。至此,一次事务提交完成。图8Binlog刷盘。最后要补充的一点是在redolog中写入commitmark。目的是为了让redolog和binlog日志保持一致。也就是说,innoDB根据commit标识来判断一个事务是否执行成功。如果在图8中的第5、6、7步,这三个步骤都必须执行成功才能提交事务。如果在执行其中一个步骤时机器出现故障怎么办?这时因为redolog中没有commit标志,所以会判断事务执行不成功,不会出现数据不一致的情况。6.后台线程将内存数据刷入磁盘。此时事务提交,缓冲池(BufferPool)中的数据已经更新。磁盘中也有redologs和binloglogs,但是此时磁盘上的数据还是旧的。啊。所以MySQL会有一个后台IO线程,会在一定的时间随机将缓冲池(BufferPool)中的数据刷新到磁盘中。图9.innoDB执行update语句时的完整流程。在后台IO线程将bufferpool中的数据flush到磁盘之前,即使MySQL宕机也没关系,因为机器重启后,会根据redolog回复之前提交的事务所做的修改。7、小结通过更新一次数据的过程,我们可以了解到innoDB存储引擎做了哪些工作。记录更新前的undo日志,更新缓冲池(BufferPool)中的数据,记录redolog日志,binlog日志。每个步骤都有其特定的功能。InnoDB确保高性能和一致性。