java执行insert_当你执行一条insert语句之后,插入的数据就立马保存在磁盘中了么?...

本文详细解析了MySQL InnoDB存储引擎中insert语句的具体流程,包括数据如何存储、changeBuffer机制及其合并时机等内容。

这么一个问题:当你执行一条insert语句之后,插入的数据就立马保存在磁盘中了么?

答案是不一定!

下面我们来看一下insert语句在写入磁盘的过程中是如何的!

我们都知道数据在提交到数据库中会有事务这一步,所以我们可以分两步来看

一、提交事务前

ded1f04f5239778b46959ca66d93720b.png

1、首先进入server层对sql会进行一些必要的检查,不会涉及到磁盘的写入。

2、进入引擎层开始正式提交执行数据。

这里我们首先来了解一下MySQL在InnoDB存储引擎中,数据是怎么存储的!

同大多数数据库一样,InnoDB有页(Page)的概念(也可以称为块),页是InnoDB磁盘管理的最小单位。在InnoDB存储引擎中,默认每个页的大小为16 KB。而从InnoDB 1.2.x版本开始,可以通过参数InnoDB_page_size将页的大小设置为4 K、8 K、16 K。若设置完成,则所有表中页的大小都为InnoDBpagesize,不可以对其再次进行修改。除非通过mysqldump导入和导出操作来产生新的库。

InnoDB的数据是按数据页为单位来读写的。也就是说,当需要读一条记录的时候,并不是将这个记录本身从磁盘读出来,而是以页为单位,将其整体读入内存。

而将数据从磁盘读入内存涉及随机IO的访问,是数据库里面成本最高的操作之一,所以为了减少磁盘IO,InnoDB设计了change buffer这个机制。

什么叫做change buffer:

①在MySQL 5.5之前的版本中,由于只支持缓存insert操作,所以最初叫做insert buffer,只是后来的版本中支持了更多的操作类型缓存,才改叫change Buffer,这也是为什么代码中有大量的ibuf前缀开头的函数或变量。

然而使用写缓冲需要同时满足两个条件:

(1) 索引是辅助索引

插入聚簇索引一般是顺序的,一般不需要磁盘的随机读取,所以不需要使用change Buffer

(2) 索引不是唯一的

辅助索引不能是唯一的,因为在插入缓冲时,数据库并不去查找索引页来判断插入的记录的唯一性。如果去查找肯定又会有离散读取的情况发生,从而导致change buffer失去了意义。

②change Buffer的底层实现

change Buffer底层结构是一颗全局的B+树,负责对所有的表空间进行change Buffer。

所以insert语句并不需要立刻将数据写入磁盘文件中,只需要修改内存缓冲池当中对应的数据页就可以了。

4、都知道内存不能保证数据的持久化,如果数据库在这个过程中宕机了,怎么保证保存在缓存中的数据不丢失。redo log 因此而生,默认情况下每次事务提交都会触发一次 redo log 刷盘。

5、如果开启了 binlog 日志,事务逻辑数据将会被写入 binlog 文件,且为了保证复制安全,建议设置为每次事务提交时,都要将 binlog 日志的变更刷入磁盘。

综上insert语句成功提交时,数据不是发生立马磁盘数据写入的,而是通过 redo log 和 binlog 文件最后把数据写入到磁盘。然而数据库缓存区不可能无限大,redo log 也很难容下所有的数据,那缓存区的数据怎么写到磁盘中呢?

二、事务提交后

f97086d0d812d0b06aab3ae76da46929.png

1、当缓冲池中的数据页达到一定量或数据库的IO压力较小时,都会进行数据页刷盘操作。

2、当开启共享表空间时,刷新数据时首先会复制一份刷入共享表空间中,由于共享表空间的页是连续的,对磁盘的写入也是顺序操作,所以这个过程对性能消耗不大。

3、不管是否经过共享表空间,更新的数据页最终还是需要刷入表空间的数据文件。刷入完成后才能释放数据库缓存当中的空间。

4、change Buffer也是数据库缓存中的一部分,当数据库缓存空间不足需要交换出部分数据更新页时,有可能将写缓冲的数据页换出,刷入共享表空间中的 change Buffer数据文件中。

5、当 innodb_stats_persistent=ON 时,插入语句所涉及到的数据就会被刷盘到 innodb_table_stats 和 innodbi_ndex_stats 这两张系统表中。

综上,一条 insert 语句的所有涉及到的数据在磁盘上会依次写入 redo log,binlog,共享表空间,最后在自己的用户表空间落定为安。

延伸:

说了数据写入到磁盘,那么change Buffer中的记录何时合并(merge)到真正的辅助索引中呢?

从上文可知Change Buffer是一棵B+树。当需要实现插入记录的辅助索引页不在缓冲池中,辅助索引记录首先会插入到这棵B+树中。

merge操作可能发生在以下几种情况下:

①辅助索引页被读到缓存中

②Change buffer bitmap页追踪到的辅助页已无可用空间

③master thread工作

第一种情况为当辅助索引页被读取到缓冲池中时,例如这在执行正常的SELECT查询操作,这时需要检查Insert Buffer Bitmap页,然后确认该辅助索引页是否有记录存放于Insert Buffer B+树中。若有,则将Insert Buffer B+树中该页的记录插入到该辅助索引页中。对该页多次的记录操作通过几次操作合并到了原有的辅助索引页中,因此性能会有大幅提高。

第二种情况Insert Buffer Bitmap 页用来追踪每个辅助索引页的可用空间,并至少有1/32页的空间。若插入辅助索引记录时检测到插入记录后可用空间会小于1/32页,则会强制进行一个合并操作,即强制读取辅助索引页,将Insert Buffer B+树中该页的记录及待插入的记录插入到辅助索引页中。这就是上述所说的第二种情况。

第三种情况就是在Master Thread线程中每秒或每10秒会进行一次Merge Change Buffer的操作,不同之处在于根据线程的工作状态每次进行merge操作的页的数量不同。

### 事务日志执行顺序 在 MySQL 的 InnoDB 存储引擎中,当执行 `INSERT` 语句时,事务日志(Redo Log 和 Undo Log)的写入顺序是严格遵循特定流程的,以确保数据的原子性和持久性。 在事务执行 `INSERT` 操作时,InnoDB 首先会记录 **Undo Log**,然后才执行 **Redo Log** 的写入。Undo Log 用于记录事务操作的逻辑反向操作,例如 `INSERT` 对应的反向操作为 `DELETE`。在执行 `INSERT` 之前,系统会先生成一条对应的 Undo Log 记录,用于在事务回滚时恢复到原始状态。Undo Log 的写入是在内存中完成的,并且会在事务提交前持久化到磁盘中的 Undo 表空间,以支持事务的回滚和多版本并发控制(MVCC)[^4]。 随后,InnoDB 会记录 **Redo Log**。Redo Log 是物理日志,用于记录数据页的修改操作。在 `INSERT` 操作中,当数据被写入到缓冲池中的数据页后,系统会生成一条 Redo Log 条目,记录该页的修改情况。Redo Log 是顺序写入的,因此其写入效率较高。Redo Log 缓冲区中的内容会在事务提交时被刷新到磁盘上的 Redo Log 文件中,以确保事务的持久性[^1]。 整个流程可以总结为: 1. 生成 Undo Log,记录 `INSERT` 操作的反向操作(`DELETE`)。 2. 在缓冲池中修改数据页,执行 `INSERT` 操作。 3. 生成 Redo Log,记录数据页的物理修改。 4. 事务提交时,Redo Log 被刷新到磁盘。 这种顺序确保了在系统崩溃恢复时,可以通过 Redo Log 恢复已提交事务的修改,并通过 Undo Log 回滚未提交的事务,从而保证事务的 ACID 特性[^3]。 ### 示例:INSERT 事务日志流程 ```sql START TRANSACTION; -- 插入一条记录 INSERT INTO users (id, name) VALUES (1, 'Alice'); COMMIT; ``` 在执行上述 SQL 时,InnoDB 的事务日志处理流程如下: - **生成 Undo Log**:系统首先生成一条 Undo Log 记录,用于记录 `DELETE FROM users WHERE id = 1`,以便在事务回滚时使用[^4]。 - **修改缓冲池中的数据页**:将 `INSERT` 操作的数据写入缓冲池中的数据页。 - **生成 Redo Log**:生成 Redo Log 条目,记录该数据页的修改内容。 - **提交事务**:事务提交时,Redo Log 被刷新到磁盘,确保事务的持久性[^1]。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值