MySQL数据写入流程(InnoDB 引擎)

增删改操作必须经过BufferPool,查询大多经过BufferPool

数据页:是innoDB引擎管理的最小内存单元,每个页大小默认16KB,页中存储的是行数据。

一个数据库表是由多个页组成

加载数据页到 Buffer Pool​​

​​检查数据页是否在内存​​:

如果要修改的数据页已在 Buffer Pool 中,直接使用

如果不在,则从磁盘加载某一页数据到 Buffer Pool(产生物理读 I/O)

记录 Undo Log​​

​​写入 Undo Log​​:

在修改数据前,先将​​旧数据​​写入 undo log(位于系统表空间或独立 undo 表空间)

用于事务回滚和 MVCC 多版本控制

​​保护机制​​:undo log 的写入本身也会被记录到 redo log(避免 undo log 丢失)

修改 Buffer Pool​​

​​内存中更新​​:

修改 Buffer Pool 中的数据页(此时磁盘数据未变)

标记该页为 ​​脏页(dirty page)​​

​​记录 Redo Log​​:

将数据页的​​物理变化​​(如"页号X偏移量Y修改为Z")写入 ​​redo log buffer​​

注意:redo log 记录的是物理变化,而非 SQL 语句

事务提交时的刷盘(关键区别)​​

根据 innodb_flush_log_at_trx_commit 参数决定

innodb_flush_log_at_trx_commit =1 (默认)

  1. ​准备阶段​

    • 事务修改数据时,先在内存的 ​​Buffer Pool​​ 中更新数据页(变成脏页)
    • 同时生成 ​​redo log​​ 记录,暂存到 ​​redo log buffer​​(内存缓冲区)
  2. ​提交阶段​

    • ​Step 1​​: 将事务的 redo log 从 redo log buffer ​​写入操作系统的 page cache​​(内存)
    • ​Step 2​​: ​​立即调用 fsync()​ 将 page cache 中的 redo log ​​强制刷入物理磁盘​
    • ​Step 3​​: 收到磁盘确认后,​标记事务提交成功​(返回客户端)
  3. ​数据页刷盘​

    • ​Buffer Pool 中的脏页​​(实际数据)由后台线程 ​​异步写入磁盘​​(与事务提交非同步)
    • 通过 checkpoint 机制控制刷脏页的时机

innodb_flush_log_at_trx_commit =2

  1. 修改阶段​

    • 事务修改数据时,先在内存的 ​​Buffer Pool​​ 中更新数据页(标记为脏页)
    • 同时生成 ​​redo log​​ 记录,写入 ​​redo log buffer​​(内存缓冲区)
  2. ​提交阶段​

    • ​Step 1​​: 将 redo log 从 redo log buffer ​​写入操作系统的 page cache​​(内存)
    • ​Step 2​​: ​立即返回事务提交成功​(无需等待 fsync() 刷盘)
    • ​Step 3​​: 后台线程​​每秒一次​​调用 fsync() 将 page cache 中的 redo log 刷入磁盘
  3. ​数据持久化​

    • ​Buffer Pool 的脏页​​由后台线程异步刷盘(与事务提交无关)
    • 即使 redo log 未刷盘,事务也​​已提交成功​​(客户端已收到确认)

innodb_flush_log_at_trx_commit =0

  1. ​完全异步写入​​:

    • 事务提交时,redo log 仅写入 ​​redo log buffer​​(内存)
    • ​不立即写入 page cache​​,更不会调用 fsync()
  2. ​定时刷盘​​:

    • 后台线程​​每秒一次​​将 redo log buffer 内容:
      • 写入操作系统的 page cache
      • 并调用 fsync() 刷入磁盘
  3. ​立即返回成功​​:

    • 事务提交请求完全不等待任何磁盘IO
    • 即使 redo log 还在内存中,也立即向客户端返回提交成功

行为特征 =1 (严格模式) =2 (实时写延迟刷) =0 (完全异步)
提交时写入位置 直接到物理磁盘 到操作系统page cache 只到InnoDB log buffer
返回客户端时机 等待磁盘IO完成 写入page cache后立即返回 写入内存后立即返回
后台刷盘频率 每次提交都刷 每秒1次 每秒1次
可能丢失的数据量 几乎不会丢失 最多1秒数据 超过1秒数据

不要redo log,buffer pool中数据直接同步行不行?

可以,但是性能极低,将buffer pool中的增删改同步刷新,保存到磁盘时都是随机的磁盘IO,性能极低。redo log同步时是顺序的磁盘IO,日志文件都是追加的,顺序的磁盘IO性能提高很多

你可能感兴趣的:(MySQL数据写入流程(InnoDB 引擎))