MySQL Update 语句执行流程
在数据库操作中,update
语句是常用的用于修改数据的命令。下面我们将详细介绍 MySQL 中 update
语句的执行流程以及相关的日志机制。
执行流程
一、update
语句执行与 buffer pool
缓冲区
执行流程概述
update
语句的整体执行流程和 select
语句类似。MySQL 要完成数据修改,会先从存储引擎层读取数据到服务层,在服务层修改数据后,再通过存储引擎层将更新后的数据写回数据库。
buffer pool
作用
InnoDB 引擎设计了 buffer pool
缓冲区,MySQL 从磁盘通过 IO 读取数据到 buffer pool
中,每次读取 16KB(16384 字节),也就是一页的数据。引擎从 buffer pool
中获取数据进行修改,然后再将修改后的数据写入 buffer pool
,基于内存的操作使得读写速度非常快。
脏数据与脏页刷新机制
buffer pool
中还未同步到磁盘的数据称为脏数据。InnoDB 的脏页刷新机制如下:
- 当脏页比例超过
innodb_max_dirty_pages_pct_lwm
的值时,开始刷新脏页到磁盘。 - 当脏页比例超过
innodb_max_dirty_pages_pct_lwm
且超过innodb_max_dirty_pages_pct
时,进入勤快刷新模式(agressively flush
),更快地刷新脏页到磁盘。 - 当 InnoDB 要重用之前的
redo
文件时,会触发sharp checkpoint
,将innodb_buffer_pool
中所有与该文件有关的页面刷新到磁盘,可能引发磁盘 IO 风暴,影响性能甚至可用性。
相关参数说明
innodb_max_dirty_pages_pct
默认值为 75,即脏页比例超过 75% 时进入勤快刷新模式。innodb_max_dirty_pages_pct_lwm
默认值是 0,此值表示不启用该功能,因此innodb_buffer_pool
中的脏页比例通常维持在 75% 左右。
buffer pool
大小与数据清理
buffer pool
默认大小为 128M,存满时 InnoDB 引擎会使用改良的 LRU 算法清理数据。LRU 算法即最近最久未使用法,MySQL 对其进行了改良。
二、redo log
日志
解决数据丢失问题
InnoDB 引擎将数据存入 buffer pool
后,如果还没来得及刷新到磁盘数据库服务就挂掉,数据可能丢失。为解决该问题,MySQL 设计了基于磁盘存储的 redo log
日志。
性能考量
虽然将数据存入 buffer pool
是为了提高性能,但现在又要存入 redo log
磁盘文件,性能会受到一定影响。不过,redo log
采用顺序磁盘 IO,即按顺序追加写入,相比随机磁盘 IO 速度更快。随机磁盘 IO 中数据分散存储在不同扇区,更新数据时会增加寻道时间,写入变慢。
刷盘策略
log buffer
刷盘时间间隔为每隔一秒,但具体刷盘策略由 innodb_flush_log_at_trx_commit
参数决定:
- 设置为 1 时,事务每次提交都会将
log buffer
中的日志写入os buffer
并调用fsync()
刷到磁盘,即使系统崩溃也不会丢失数据,但 IO 性能较差。 - 设置为 0 时,事务提交时不将
log buffer
中日志写入os buffer
,而是每秒写入并调用fsync()
写入磁盘,系统崩溃会丢失 1 秒钟的数据。 - 设置为 2 时,每次提交仅写入
os buffer
,每秒调用fsync()
将os buffer
中的日志写入磁盘。
三、undo log
日志
undo log
可称为撤销日志或回滚日志,从事务角度保证事务的原子性。日志中记录反向操作,例如将 username
从 “张三” 修改为 “赵四”,undo log
会记录原来的值 “张三”,以便数据库进行回滚操作时恢复数据。
四、bin log
日志
bin log
即二进制日志,属于 MySQL 服务层的日志。它记录所有数据库表结构变更(如 CREATE
、ALTER TABLE
等)以及表数据修改(如 INSERT
、UPDATE
、DELETE
等),但不记录 SELECT
和 SHOW
这类不修改数据的操作,可通过查询通用日志查看所有执行语句。bin log
主要用于主从复制和数据恢复。
五、总结
MySQL 的 update
语句执行过程涉及 buffer pool
缓冲区提高读写性能,同时通过 redo log
、undo log
和 bin log
三种日志机制保障数据的安全性、可恢复性和事务的原子性,以及实现主从复制等功能。不同日志机制相互配合,使得 MySQL 在保证数据可靠性的同时,尽可能提高性能。