分析两个场景:
1.更新id列,更新前后值一样,也就是Rows matched: 1 Changed: 0,会写数据吗?
mysql> update cjc.t1 set id=5 where id=5;
Query OK, 0 rows affected (0.00 sec)
Rows matched: 1 Changed: 0 Warnings: 0
2.更新id列,没有匹配的值,也就是Rows matched: 0 Changed: 0,会写数据吗?
mysql> update cjc.t1 set id=5 where id=5000;
Query OK, 0 rows affected (0.00 sec)
Rows matched: 0 Changed: 0 Warnings: 0
注意:不考虑触发器、主外键约束、ON UPDATE CURRENT_TIMESTAMP 等场景。
回答这个问题前,先思考可能会向哪些文件写入数据:
1:t1.ibd
2:redo log file
3:undo log file
4:binlog
5.Doublewrite Buffer Files(ib_*.dblwr)
测试环境说明:
MySQL 8.0.33
binlog_format=ROW
测试结果:
以上两个场景,有数据写入的文件有:
1:redo log file
2:undo log file
3.Doublewrite Buffer Files(ib_*.dblwr)
没有数据写入的文件有:
1:t1.ibd
2:binlog
如果是 binlog_format=STATEMENT,理论上会binlog有数据写入。
测试过程如下:
查看参数:
mysql> select version();
+-----------+
| version() |
+-----------+
| 8.0.33 |
+-----------+
1 row in set (0.00 sec)
mysql> show variables like 'log_bin';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| log_bin | ON |
+---------------+-------+
1 row in set (0.00 sec)
mysql> show variables like 'binlog_format';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| binlog_format | ROW |
+---------------+-------+
1 row in set (0.00 sec)
创建测试数据:
use cjc;
CREATE TABLE t1(id int,time time);
insert into t1 values(1,now());
insert into t1 values(2,now());
insert into t1 values(3,now());
insert into t1 values(4,now());
insert into t1 values(5,now());
flush logs;
记录更新前的信息:
mysql> select * from cjc.t1;
+------+----------+
| id | time |
+------+----------+
| 1 | 14:28:46 |
| 2 | 14:28:49 |
| 3 | 14:28:52 |
| 4 | 14:31:04 |
| 5 | 14:42:35 |
+------+----------+
5 rows in set (0.00 sec)
mysql> SHOW GLOBAL STATUS LIKE 'Innodb_data_writes';
+--------------------+-------+
| Variable_name | Value |
+--------------------+-------+
| Innodb_data_writes | 1629 |
+--------------------+-------+
1 row in set (0.00 sec)
mysql> SHOW GLOBAL STATUS LIKE 'Innodb_os_log_written';
+-----------------------+--------+
| Variable_name | Value |
+-----------------------+--------+
| Innodb_os_log_written | 282112 |
+-----------------------+--------+
1 row in set (0.00 sec)
数据文件 t1.ibd:
ls -lrth /mysqldata/13309/data/cjc/t1.ibd
-rw-r----- 1 mysql mysql 112K May 28 14:42 /mysqldata/13309/data/cjc/t1.ibd
stat /mysqldata/13309/data/cjc/t1.ibd
File: ‘/mysqldata/13309/data/cjc/t1.ibd’
Size: 114688 Blocks: 224 IO Block: 4096 regular file
Device: fd02h/64770d Inode: 6089419 Links: 1
Access: (0640/-rw-r-----) Uid: ( 621/ mysql) Gid: ( 621/ mysql)
Access: 2025-05-28 14:28:21.624665631 +0800
Modify: 2025-05-28 14:42:35.527944136 +0800
Change: 2025-05-28 14:42:35.527944136 +0800
Birth: -
undo 文件undo_001,undo_002:
ls -lrth /mysqldata/13309/undo/undo_00*
-rw-r----- 1 mysql mysql 16M May 28 14:42 /mysqldata/13309/undo/undo_002
-rw-r----- 1 mysql mysql 16M May 28 14:42 /mysqldata/13309/undo/undo_001
stat /mysqldata/13309/undo/undo_00*
File: ‘/mysqldata/13309/undo/undo_001’
Size: 16777216 Blocks: 32768 IO Block: 4096 regular file
Device: fd02h/64770d Inode: 33800442 Links: 1
Access: (0640/-rw-r-----) Uid: ( 621/ mysql) Gid: ( 621/ mysql)
Access: 2025-05-22 11:09:11.493664080 +0800
Modify: 2025-05-28 14:42:51.532240296 +0800
Change: 2025-05-28 14:42:51.532240296 +0800
Birth: -
File: ‘/mysqldata/13309/undo/undo_002’
Size: 16777216 Blocks: 32768 IO Block: 4096 regular file
Device: fd02h/64770d Inode: 33800443 Links: 1
Access: (0640/-rw-r-----) Uid: ( 621/ mysql) Gid: ( 621/ mysql)
Access: 2025-05-22 11:09:11.497664152 +0800
Modify: 2025-05-28 14:42:51.532240296 +0800
Change: 2025-05-28 14:42:51.532240296 +0800
Birth: -
binlog文件:mysql-bin.000021
ls -lrth /mysqldata/13309/binlog/mysql-bin.000021
-rw-r----- 1 mysql mysql 237 May 28 14:42 /mysqldata/13309/binlog/mysql-bin.000021
stat /mysqldata/13309/binlog/mysql-bin.000021
File: ‘/mysqldata/13309/binlog/mysql-bin.000021’
Size: 237 Blocks: 8 IO Block: 4096 regular file
Device: fd02h/64770d Inode: 101937603 Links: 1
Access: (0640/-rw-r-----) Uid: ( 621/ mysql) Gid: ( 621/ mysql)
Access: 2025-05-28 14:42:50.748225953 +0800
Modify: 2025-05-28 14:42:50.744225880 +0800
Change: 2025-05-28 14:42:50.744225880 +0800
Birth: -
redo log file文件:#ib_redo0
ls -lrth /mysqldata/13309/redo/#innodb_redo/#ib_redo0
-rw-r----- 1 mysql mysql 64M May 28 14:44 /mysqldata/13309/redo/#innodb_redo/#ib_redo0
stat /mysqldata/13309/redo/#innodb_redo/#ib_redo0
File: ‘/mysqldata/13309/redo/#innodb_redo/#ib_redo0’
Size: 67108864 Blocks: 131072 IO Block: 4096 regular file
Device: fd02h/64770d Inode: 6089452 Links: 1
Access: (0640/-rw-r-----) Uid: ( 621/ mysql) Gid: ( 621/ mysql)
Access: 2025-05-22 11:09:11.965672530 +0800
Modify: 2025-05-28 14:44:32.266053036 +0800
Change: 2025-05-28 14:44:32.266053036 +0800
Birth: -
执行 update 操作,更新前后值相同:
mysql> update cjc.t1 set id=5 where id=5;
Query OK, 0 rows affected (0.00 sec)
Rows matched: 1 Changed: 0 Warnings: 0
有数据写入:update 前 1629 后 1652;
# 堆代码 duidaima.com
mysql> SHOW GLOBAL STATUS LIKE 'Innodb_data_writes';
+--------------------+-------+
| Variable_name | Value |
+--------------------+-------+
| Innodb_data_writes | 1652 |
+--------------------+-------+
1 row in set (0.00 sec)
有数据写入:update 前 282112 后 283136;
mysql> SHOW GLOBAL STATUS LIKE 'Innodb_os_log_written';
+-----------------------+--------+
| Variable_name | Value |
+-----------------------+--------+
| Innodb_os_log_written | 283136 |
+-----------------------+--------+
1 row in set (0.00 sec)
数据文件 t1.ibd:update 前后没有数据写入
ls -lrth /mysqldata/13309/data/cjc/t1.ibd
-rw-r----- 1 mysql mysql 112K May 28 14:42 /mysqldata/13309/data/cjc/t1.ibd
stat /mysqldata/13309/data/cjc/t1.ibd
File: ‘/mysqldata/13309/data/cjc/t1.ibd’
Size: 114688 Blocks: 224 IO Block: 4096 regular file
Device: fd02h/64770d Inode: 6089419 Links: 1
Access: (0640/-rw-r-----) Uid: ( 621/ mysql) Gid: ( 621/ mysql)
Access: 2025-05-28 14:28:21.624665631 +0800
Modify: 2025-05-28 14:42:35.527944136 +0800
Change: 2025-05-28 14:42:35.527944136 +0800
Birth: -
undo 文件undo_001,undo_002:update 前后 有数据写入
ls -lrth /mysqldata/13309/undo/undo_00*
-rw-r----- 1 mysql mysql 16M May 28 14:44 /mysqldata/13309/undo/undo_001
-rw-r----- 1 mysql mysql 16M May 28 14:44 /mysqldata/13309/undo/undo_002
stat /mysqldata/13309/undo/undo_00*
File: ‘/mysqldata/13309/undo/undo_001’
Size: 16777216 Blocks: 32768 IO Block: 4096 regular file
Device: fd02h/64770d Inode: 33800442 Links: 1
Access: (0640/-rw-r-----) Uid: ( 621/ mysql) Gid: ( 621/ mysql)
Access: 2025-05-22 11:09:11.493664080 +0800
Modify: 2025-05-28 14:44:31.534039941 +0800
Change: 2025-05-28 14:44:31.534039941 +0800
Birth: -
File: ‘/mysqldata/13309/undo/undo_002’
Size: 16777216 Blocks: 32768 IO Block: 4096 regular file
Device: fd02h/64770d Inode: 33800443 Links: 1
Access: (0640/-rw-r-----) Uid: ( 621/ mysql) Gid: ( 621/ mysql)
Access: 2025-05-22 11:09:11.497664152 +0800
Modify: 2025-05-28 14:44:31.542040084 +0800
Change: 2025-05-28 14:44:31.542040084 +0800
Birth: -
binlog文件:mysql-bin.000021:update 前后 没有数据写入
如果 binlog_format=STATEMENT ,理论上会有写入。
ls -lrth /mysqldata/13309/binlog/mysql-bin.000021
-rw-r----- 1 mysql mysql 237 May 28 14:42 /mysqldata/13309/binlog/mysql-bin.000021
stat /mysqldata/13309/binlog/mysql-bin.000021
-rw-r----- 1 mysql mysql 237 May 28 14:42 /mysqldata/13309/binlog/mysql-bin.000021
mysql@SATEST-DAW-004:/home/mysql$stat /mysqldata/13309/binlog/mysql-bin.000021
File: ‘/mysqldata/13309/binlog/mysql-bin.000021’
Size: 237 Blocks: 8 IO Block: 4096 regular file
Device: fd02h/64770d Inode: 101937603 Links: 1
Access: (0640/-rw-r-----) Uid: ( 621/ mysql) Gid: ( 621/ mysql)
Access: 2025-05-28 14:42:50.748225953 +0800
Modify: 2025-05-28 14:42:50.744225880 +0800
Change: 2025-05-28 14:42:50.744225880 +0800
Birth: -
redo log file文件:#ib_redo0:update 前后 有数据写入
ls -lrth /mysqldata/13309/redo/#innodb_redo/#ib_redo0
-rw-r----- 1 mysql mysql 64M May 28 14:47 /mysqldata/13309/redo/#innodb_redo/#ib_redo0
stat /mysqldata/13309/redo/#innodb_redo/#ib_redo0
File: ‘/mysqldata/13309/redo/#innodb_redo/#ib_redo0’
Size: 67108864 Blocks: 131072 IO Block: 4096 regular file
Device: fd02h/64770d Inode: 6089452 Links: 1
Access: (0640/-rw-r-----) Uid: ( 621/ mysql) Gid: ( 621/ mysql)
Access: 2025-05-22 11:09:11.965672530 +0800
Modify: 2025-05-28 14:47:12.280858841 +0800
Change: 2025-05-28 14:47:12.280858841 +0800
Birth: -
使用 strace 跟踪写入操作过程:
查看 mysqld pid = 27960
ps -ef | grep mysqld
查看当前 Connection id:776
mysql> \s
--------------
mysql Ver 8.0.33 for Linux on x86_64 (MySQL Community Server - GPL)
Connection id: 776
Current database: cjc
mysql> SELECT THREAD_ID,THREAD_OS_ID,PROCESSLIST_ID,NAME FROM performance_schema.threads where PROCESSLIST_ID=776;
+-----------+--------------+----------------+---------------------------+
| THREAD_ID | THREAD_OS_ID | PROCESSLIST_ID | NAME |
+-----------+--------------+----------------+---------------------------+
| 823 | 28029 | 776 | thread/sql/one_connection |
+-----------+--------------+----------------+---------------------------+
1 row in set (0.00 sec)
使用 strace 跟踪写入相关的系统调用:
跟踪线程
strace -f -p 28029 -e trace=file,write,pwrite64,fsync,fdatasync -o /mysqldata/dbtmpfile/mysql_trace_20250528.log
跟踪主进程
strace -f -p 27960 -e trace=file,write,pwrite64,fsync,fdatasync -s 256 -o /mysqldata/dbtmpfile/mysql_trace_all_20250528.log
参数说明:
-e trace=write,pwrite64,fsync,fdatasync`:仅跟踪文件写入和同步操作。
-o:将输出保存到文件。
再次执行:
mysql> update cjc.t1 set id=5 where id=5;
Query OK, 0 rows affected (0.01 sec)
Rows matched: 1 Changed: 0 Warnings: 0
执行 strace 的窗口,按 Ctrl+C 终止 strace
查看 mysql_trace_20250528.log:
ls -lrth mysql_trace_20250528.log
-rw-r--r-- 1 root root 1.1K May 28 15:44 mysql_trace_20250528.log
分析 trace 日志:
cat mysql_trace_20250528.log
27995 pwrite64(11</mysqldata/13309/redo/#innodb_redo/#ib_redo0>, "\0\1e\242\0\223\0'\0\0\0\1_\0006\0\4\373\357_\08\373\377\2\373\357_\0<\0\4"..., 512, 46868992) = 512
27993 fsync(11</mysqldata/13309/redo/#innodb_redo/#ib_redo0>) = 0
27987 pwrite64(5</mysqldata/13309/data/#ib_16384_0.dblwr>, "\302U\310\266\0\0\0\5\0\0\0\0\0\0\0\0\0\0\0\0\2\313B\223\0\7\0\0\0\0\0\0"..., 16384, 786432) = 16384
27982 fsync(10</mysqldata/13309/data/ibdata1>) = 0
27991 stat("/mysqldata/13309/redo/#innodb_redo/#ib_redo0", {st_mode=S_IFREG|0640, st_size=67108864, ...}) = 0
27991 openat(AT_FDCWD, "/mysqldata/13309/redo/#innodb_redo/#ib_redo0", O_RDWR) = 48</mysqldata/13309/redo/#innodb_redo/#ib_redo0>
27991 lstat("/mysqldata", {st_mode=S_IFDIR|0755, st_size=156, ...}) = 0
27991 lstat("/mysqldata/13309", {st_mode=S_IFDIR|0755, st_size=143, ...}) = 0
27991 lstat("/mysqldata/13309/redo", {st_mode=S_IFDIR|0755, st_size=26, ...}) = 0
27991 lstat("/mysqldata/13309/redo/#innodb_redo", {st_mode=S_IFDIR|0750, st_size=4096, ...}) = 0
27991 pwrite64(48</mysqldata/13309/redo/#innodb_redo/#ib_redo0>, "\0\0\0\0\0\0\0\0\0\0\0\0\2\313B\223\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 512, 1536) = 512
27991 fsync(48</mysqldata/13309/redo/#innodb_redo/#ib_redo0>) = 0
27991 fsync(48</mysqldata/13309/redo/#innodb_redo/#ib_redo0>) = 0
查看帮助信息:
man 2 pwrite64
pwrite() writes up to count bytes from the buffer starting at buf to the file descriptor fd at offset offset.
The file offset is not changed.
The file referenced by fd must be capable of seeking.
SELECT THREAD_ID,THREAD_OS_ID,PROCESSLIST_ID,NAME FROM performance_schema.threads where THREAD_OS_ID in (27995,27993,27987,27982,27991);
+-----------+--------------+----------------+---------------------------------------------+
| THREAD_ID | THREAD_OS_ID | PROCESSLIST_ID | NAME |
+-----------+--------------+----------------+---------------------------------------------+
| 15 | 27982 | NULL | thread/innodb/io_write_thread |
| 20 | 27987 | NULL | thread/innodb/page_flush_coordinator_thread |
| 24 | 27991 | NULL | thread/innodb/log_checkpointer_thread |
| 26 | 27993 | NULL | thread/innodb/log_flusher_thread |
| 28 | 27995 | NULL | thread/innodb/log_writer_thread |
+-----------+--------------+----------------+---------------------------------------------+
5 rows in set (0.00 sec)
其中:ib_16384_0.dblwr 属于 Doublewrite Buffer Files。