数据库系列3:InnoDB的结构和更新语句执行的详细过程

上一节介绍了更新语句的基本过程,除了更新数据库表,还要更新undo和redo log,但是具体是怎么操作的呢?发生事务问题时又是如何处理的呢?为此我们要先看一下InnoDB的总体结构。

1.InnoDB的总体结构

整体结构为:
在这里插入图片描述

2. 内存结构

Buffer Pool 主要分为三个部分:Buffer Pool,change buffer,Adaptive hash Index,另外还有一个log buffer。

2.1 BufferPool

缓存的是页面信息,包括数据也和索引页。默认大小是128M,可以调整。
可以通过下面的命令查看

show variables like '%innodb_buffer_pool%';

在这里插入图片描述

如果要看状态,可以用这个命令

show status like '%innodb_buffer_pool%';

如果写满了,则使用LRU算法来替换

2.3 Change Buffer 写缓冲

Change buffer是Buffer Pool的一部分。如果这个数据也不是唯一索引,不存在数据重复的情况,也就不需要从磁盘加载索引页判断数据是否重复(唯一性检查)。这种情况下先把修改记录在内存的缓冲区中,从而提升更新语句的执行速度。这块区域就是Change Buffer。
最后把Change Buffer记录到数据页的操作叫做merge。什么时候发生merge?有几种情况:在访问这个数据页的时候,或者通过后台线程,或者数据库shut down,redo log写满时触发。
如果数据库大部分索引都是非唯一索引,并且业务是写多读少,不会再写数据后立即读取,就可以使用CB。可以调大这个值来支持写多读少的情况。也就是CB占BP的的比例,默认是25%。

2.4 Adaptive hash index

索引应放在磁盘的,为什么要专门把一种hash的索引放到内存?在索引部分再讨论。

2.5 Redo log Buffer

Redo log也不是每一次都直接写入磁盘,在BP里面有一块内存区域(Log Buffer)专门用来保存即将要写入日志文件的数据,默认16M。
redo log的内容主要用于崩溃恢复。磁盘的数据文件,数据来自BP。redo log写入到磁盘,而不写入数据文件。
Log Buffer 什么时候写入到log file?
在我们写入数据到磁盘的时候,OS本身是有缓存的,flush就是将OS缓冲区写入到磁盘。
写入的时机也是可以配置的,一般由三种:
0:延迟写,每秒一次写入log file,并且fulsh同时进行,此时提交事务时,不会主动触发写入磁盘的操作。
1:每次提交事务时写入,同时刷盘。(默认)
2:实时写,每次提交事务写log,但是每秒一次flush。

3. 磁盘结构

表空间可以看做是InnoDB存储引擎逻辑结构的最高层,所有的数据都存在表空间里。InnoDB的表空间分为5类

3.1.系统表空间 systemtablespace

在默认情况下InnoDB存储引擎有一个共享表空间,也叫系统表空间,包含InnoDB数据字典和双写缓冲区,change Buffer和Undo logs。
undo 后面单独看。
数据字典:由内部系统表组恒,存储表和索引的元数据
双写缓冲区。
双写缓冲区
InnoDb的页和OS的页大小不一致,InnoDB的是16K,OS的是4K,因此InnodB的页写入时,一个页需要分4次写。
如果存储引擎正在写时发生宕机,可能出现页只写了一部分的情况,这叫做部分写失效。
由于此时某个页已经破坏了,无法通过redo log来修复,此时只能通过一个页的副本来进行,这就是双写技术。
https://blog.csdn.net/shenjian58/article/details/103501888
跟redo log一样,double wire 由两部分组成,一部分是内存的double write,一部分是磁盘的double write。因为double write是顺序写入的,不会带来太大的开销。DWB由128个页构成,容量只有2M。
具体执行过程为:
第一步:页数据先memcopy到DWB的内存里;
第二步:DWB的内存里,会先刷到DWB的磁盘上;
第三步:DWB的内存里,再刷到数据磁盘存储上;
步骤2和步骤3要写2次磁盘,这就是“Double Write”的由来。
能够通过DWB保证页数据的完整性,但毕竟DWB要写两次磁盘,会不会导致数据库性能急剧降低呢?
分析DWB执行的三个步骤:
(1)第一步,页数据memcopy到DWB的内存,速度很快;
(2)第二步,DWB的内存fsync刷到DWB的磁盘,属于顺序追加写,速度也很快;
(3)第三步,刷磁盘,随机写,本来就需要进行,不属于额外操作;
128页(每页16K)2M的DWB,会分两次刷入磁盘,每次最多64页,即1M的数据,执行也是非常之快的。
根据第三方测评,该方式损失大约10%的性能。

3.2 独占表空间 file-pre-table tablespace

开启后,为每个表单独占一个表空间。
但是其他的数据,例如回滚信息,插冲索引页,系统事务信息,双写信息等都还是放在原来的共享表空间里的。

3.3 通用表空间

通用表空间也是一种共享的表空间,看相关说明,功能存储不同数据库的表,还能自定义数据路径和文件,其他没看出来有啥用。

3.4 临时表空间

存储临时表的数据,包括用户创建的临时表,服务器重启时会被删除重建。

3.5 undo log 空间

undo log默认在系统表空间ibdata1文件中,因为共享表空间不会自动收缩,也可以单独创建一个undo表空间。

4.后台线程

后台线程的主要作用是负责刷新内存池和把修改的数据页刷新到磁盘上,后台线程有master thread,IO thread,purge thread,page cleaner thread几种。
master thread 负责刷新缓存数据到磁盘并协调调度其他后台进程。
IOthread 分为insert buffer,log,read,write 线程,分别用来处理insert buffer,重做日志和读写请求的IO回调。
purge thread 用来回收 undo 页。
page cleaner thread 用来刷新脏页。

5.binlog

binlog以事件的形式记录了所有的DDL和DML语句,可以用来做主从复制和数据恢复。跟redo log 不一样,它的文件是可以追加的,没有固定大小限制。
在开启了binlog的时候,我们可以把binlog 导出成SQL语句,把所有的操作重放一遍,来实现数据的恢复。
binlog的另一个功能是用来实现主从复制,原理就是从服务器读取主服务器的binlog,然后执行一遍。

6.完整的更新过程:

有了这两个日志之后,再看一下update如何执行的:
例如更新一条语句

 update teacher set name=‘new’ where id=1;

完整的执行过程为:
1.update teacher set name =“new_name” where id=1;
2.将Id=1的行上的name列值改为"new_name"
3.将修改的结果更新到内存。
4.记录redolog,并将这行记录状态设置为prepare
5.修改好了之后,存储引擎向Server层提交事务
6.写入binlog
7.server层向存储引擎提交事务commit
8.将redo log 里这个事务的相关记录状态设置为commit

上面有几个重点:
1.先记录到内存,再写日志文件。
2.记录redo log分为两个阶段,也就是4和8。
3.存储引擎和Server记录不同的日志。
4.先记录redo,再记录binlog。

两阶段提交
这里为什么redo log要分为两个阶段?
假如我们执行的是把name改成new_name了,如果写完redo log,还没有写binlog的时候,mysql重启了。此时用redo log恢复的是new_name,所以写入磁盘的是new_name,但是binlog里没有记录这个逻辑日志,所以这时候binlog恢复数据或者同步到从库时就会出现数据不一致的情况。
所以在写两个日志的情况下,binlog就充当了一个事务的协调者。通知InnoDB来执行prepare或者commit或者rollback。如果⑥写binlog失败,就不会提交。
此时的判断是否提交的逻辑是
在这里插入图片描述

上面就是更新的完整过程。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

纵横千里,捭阖四方

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值