一条更新SQL,究竟发生了什么?

缓冲池

InnoDB存储引擎中有一个非常重要的放在内存里的组件,就是缓冲池(Buffer Pool),这里面会缓存很多的数据,以便于以后在查询的时候,万一你要是内存缓冲池里有数据,就可以不用去查磁盘了,我们看下图。
在这里插入图片描述
我们的Java系统对数据库执行的增删改操作,其实主要就是对这个内存数据结构中的缓存数据执行的。

配置Buffer Pool大小

Buffer Pool本质其实就是数据库的一个内存组件,一片内存数据结构,所以这个内存数据结构肯定是有一定的大小的,不可能是无限大的。

Buffer Pool默认情况下是128MB,这个大小其实是偏小的,我们可以配置Buffer Pool的大小,比如给他分配个2G的内存。
使用下面的配置就行。

innodb_buffer_pool_size = 2147483648

数据页

好了,现在我们有了这个内存缓冲池了,而我们知道数据库中的数据无非就是一些数据表啊,表中有很多行,每行有很多个字段,那么我们的数据是一行一行的放在这个缓冲池的吗?

实际上MySQL对数据抽象出来了一个数据页的概念,他是把很多行数据放在了一个数据页里,也就是说我们的磁盘文件中就是会有很多的数据页,每一页数据里放了很多行数据。

在这里插入图片描述
Buffer Pool中默认情况下,一个缓存页的大小和磁盘上的一个数据页的大小是一一对应起来的,都是16KB。

缓存页对应的描述信息

其实每个缓存页,实际上都会有一个描述信息,这个描述信息是用来描述这个缓存页的,他描述了这个数据页所属的表空间、数据页的编号、这个缓存页在Buffer Pool中的地址以及别的一些信息。这个描述信息本身也是一块数据,在Buffer Pool中,每个缓存页的描述数据放在最前面,然后各个缓存页放在后面。

在这里插入图片描述
Buffer Pool中的描述数据也是要占据内存空间的,所以实际上Buffer Pool真正的最终大小会超出一些你设置的大小,因为他里面还要存放每个缓存页的描述数据。

来看看一条更新语句的执行流程

存储引擎要执行更新语句的时候 ,比如对“id=1”这一行数据进行更新,他会先看看“id=1”这一行数据是否在缓冲池里,如果不在会直接从磁盘里加载到缓冲池里来,而且接着还会对这行记录加独占锁。
undo日志文件
在更新之前其实会把原来的值写入到undo日志文件中去,方便我们进行回滚。
在这里插入图片描述
写入undo日志后我们就可以更新buffer pool中的缓存数据了,更新完成后这个数据就是脏数据

那么为什么说此时这行数据就是脏数据了呢?
因为这个时候磁盘上这行数据还是原来的值,但是内存里这行数据已经被修改了,所以就会叫他脏数据。

Redo Log Buffer
现在已经把内存里的数据进行了修改,但是磁盘上的数据还没修改,那么此时万一MySQL所在的机器宕机了,必然会导致内存里修改过的数据丢失,这怎么办呢?
这个时候,就必须要把对内存所做的修改写入到一个Redo Log Buffer里去,这也是内存里的一个缓冲区,是用来存放redo日志的。
所谓的redo日志,就是记录下来你对数据做了什么修改,然后在MySQL突然宕机的时候,用来恢复你更新过的数据的。
在这里插入图片描述
接着我们提交一个事务时,就会根据一定的策略把redo日志从redo log buffer里刷入到磁盘文件里去。
此时这个策略是通过innodb_flush_log_at_trx_commit来配置的,他有几个选项。

innodb_flush_log_at_trx_commit
0:提交事务时,不会把redo log buffer里的数据刷入磁盘文件的。
1:提交事务时,把redo log从内存刷入到磁盘文件里去,只要事务提交成功,那么redo log就必然在磁盘里了。
2:提交事务时,把redo日志写入磁盘文件对应的os cache缓存里去,由操作系统异步刷盘。

在这里插入图片描述
MySQL binlog
redo log是一种偏向物理性质的重做日志,是属于InnoDB存储引擎特有的一个东西。
而binlog叫做归档日志,是记录所有数据库表结构变更(例如CREATE、ALTER TABLE…)以及表数据修改(INSERT、UPDATE、DELETE…)的二进制日志。
binlog不是InnoDB存储引擎特有的日志文件,是属于mysql server自己的日志文件。

而在提交事务的时候,同时会写入binlog,并且还会把这次更新对应的binlog日志写入到磁盘文件中去,如下图所示。
在这里插入图片描述
binlog刷盘参数

sync_binlog参数可以控制binlog的刷盘策略
默认值0,此时你把binlog写入磁盘的时候,其实不是直接进入磁盘文件,而是进入os cache内存缓存。
1,此时会强制在提交事务的时候,把binlog直接写入到磁盘文件里去。

当我们把binlog写入磁盘文件之后,接着就会完成最终的事务提交,此时会把本次更新对应的binlog文件名称和这次更新的binlog日志在文件里的位置,都写入到redo log日志文件里去,同时在redo log日志文件里写入一个commit标记。
在这里插入图片描述
注意:必须是在redo log中写入最终的事务commit标记了,然后此时事务才算提交成功。

后台IO线程随机将内存更新后的脏数据刷回磁盘
提交一个事务后内存里的值也修改了,但是磁盘还没有真正修改啊。
所以MySQL有一个后台的IO线程,会在之后某个时间里,随机的把内存buffer pool中的修改后的脏数据给刷回到磁盘上的数据文件里去。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值