共计 6487 个字符,预计需要花费 17 分钟才能阅读完成。
背景
本文主要测试 MySQL 执行 update 语句时,针对与原数据(即未修改)相同的 update 语句会在 MySQL 内部重新执行吗?
测试环境
MySQL5.7.25
Centos 7.4
binlog_format 为 ROW
参数
root@localhost : (none) 04:53:15> show variables like ‘binlog_row_image’;
+——————+——-+
| Variable_name | Value |
+——————+——-+
| binlog_row_image | FULL |
+——————+——-+
1 row in set (0.00 sec)
root@localhost : (none) 04:53:49> show variables like ‘binlog_format’;
+—————+——-+
| Variable_name | Value |
+—————+——-+
| binlog_format | ROW |
+—————+——-+
1 row in set (0.00 sec)
root@localhost : test 05:15:14> show variables like ‘transaction_isolation’;
+———————–+—————–+
| Variable_name | Value |
+———————–+—————–+
| transaction_isolation | REPEATABLE-READ |
+———————–+—————–+
1 row in set (0.00 sec)
测试步骤
session1
root@localhost : test 04:49:48> begin;
Query OK, 0 rows affected (0.00 sec)
root@localhost : test 04:49:52> select * from test where id =1;
+—-+——+——+——+
| id | sid | mid | name |
+—-+——+——+——+
| 1 | 999 | 871 | NW |
+—-+——+——+——+
1 row in set (0.00 sec)
root@localhost : (none) 04:54:03> show engine innodb status\Gshow master status\G
…
—
LOG
—
Log sequence number 12090390
Log flushed up to 12090390
Pages flushed up to 12090390
Last checkpoint at 12090381
0 pending log flushes, 0 pending chkp writes
33 log i/o’s done, 0.00 log i/o’s/second
*************************** 1. row ***************************
File: mysql-bin.000001
Position: 154
Binlog_Do_DB:
Binlog_Ignore_DB:
Executed_Gtid_Set:
1 row in set (0.00 sec)
session2
root@localhost : test 04:47:45> update test set sid=55 where id =1;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1 Changed: 1 Warnings: 0
root@localhost : (none) 04:54:03> show engine innodb status\Gshow master status\G
…
—
LOG
—
Log sequence number 12091486
Log flushed up to 12091486
Pages flushed up to 12091486
Last checkpoint at 12091477
0 pending log flushes, 0 pending chkp writes
39 log i/o’s done, 0.00 log i/o’s/second
*************************** 1. row ***************************
File: mysql-bin.000001
Position: 500
Binlog_Do_DB:
Binlog_Ignore_DB:
Executed_Gtid_Set: 8392d215-4928-11e9-a751-0242ac110002:1
1 row in set (0.00 sec)
session1
root@localhost : test 04:49:57> update test set sid=55 where id =1;
Query OK, 0 rows affected (0.00 sec)
Rows matched: 1 Changed: 0 Warnings: 0
root@localhost : (none) 04:54:03> show engine innodb status\Gshow master status\G
…
—
LOG
—
Log sequence number 12091486
Log flushed up to 12091486
Pages flushed up to 12091486
Last checkpoint at 12091477
0 pending log flushes, 0 pending chkp writes
39 log i/o’s done, 0.00 log i/o’s/second
*************************** 1. row ***************************
File: mysql-bin.000001
Position: 500
Binlog_Do_DB:
Binlog_Ignore_DB:
Executed_Gtid_Set: 8392d215-4928-11e9-a751-0242ac110002:1
1 row in set (0.00 sec)
root@localhost : test 04:52:05> select * from test where id =1;
+—-+——+——+——+
| id | sid | mid | name |
+—-+——+——+——+
| 1 | 999 | 871 | NW |
+—-+——+——+——+
1 row in set (0.00 sec)
root@localhost : test 04:52:42> commit;
Query OK, 0 rows affected (0.00 sec)
root@localhost : test 04:52:52> select * from test where id =1;
+—-+——+——+——+
| id | sid | mid | name |
+—-+——+——+——+
| 1 | 55 | 871 | NW |
+—-+——+——+——+
1 row in set (0.00 sec)
总结
在 binlog_format=row 和 binlog_row_image=FULL 时,由于 MySQL 需要在 binlog 里面记录所有的字段,所以在读数据的时候就会把所有数据都读出来,那么重复数据的 update 不会执行。即 MySQL 调用了 InnoDB 引擎提供的“修改为 (1,55)”这个接口,但是引擎发现值与原来相同,不更新,直接返回
binlog_format 为 STATEMENT
参数
root@localhost : (none) 04:53:15> show variables like ‘binlog_row_image’;
+——————+——-+
| Variable_name | Value |
+——————+——-+
| binlog_row_image | FULL |
+——————+——-+
1 row in set (0.00 sec)
root@localhost : (none) 05:16:08> show variables like ‘binlog_format’;
+—————+———–+
| Variable_name | Value |
+—————+———–+
| binlog_format | STATEMENT |
+—————+———–+
1 row in set (0.00 sec)
root@localhost : test 05:15:14> show variables like ‘transaction_isolation’;
+———————–+—————–+
| Variable_name | Value |
+———————–+—————–+
| transaction_isolation | REPEATABLE-READ |
+———————–+—————–+
1 row in set (0.00 sec)
测试步骤
session1
root@localhost : test 05:16:42> begin;
Query OK, 0 rows affected (0.00 sec)
root@localhost : test 05:16:44> select * from test where id =1;
+—-+——+——+——+
| id | sid | mid | name |
+—-+——+——+——+
| 1 | 111 | 871 | NW |
+—-+——+——+——+
1 row in set (0.00 sec)
root@localhost : (none) 05:16:51> show engine innodb status\Gshow master status\G
…
—
LOG
—
Log sequence number 12092582
Log flushed up to 12092582
Pages flushed up to 12092582
Last checkpoint at 12092573
0 pending log flushes, 0 pending chkp writes
45 log i/o’s done, 0.00 log i/o’s/second
*************************** 1. row ***************************
File: mysql-bin.000001
Position: 154
Binlog_Do_DB:
Binlog_Ignore_DB:
Executed_Gtid_Set:
1 row in set (0.00 sec)
session2
root@localhost : test 05:18:30> update test set sid=999 where id =1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
root@localhost : (none) 05:18:47> show engine innodb status\Gshow master status\G
…
—
LOG
—
Log sequence number 12093678
Log flushed up to 12093678
Pages flushed up to 12093678
Last checkpoint at 12093669
0 pending log flushes, 0 pending chkp writes
51 log i/o’s done, 0.14 log i/o’s/second
*************************** 1. row ***************************
File: mysql-bin.000001
Position: 438
Binlog_Do_DB:
Binlog_Ignore_DB:
Executed_Gtid_Set: 8392d215-4928-11e9-a751-0242ac110002:1
1 row in set (0.00 sec)
session1
root@localhost : test 05:16:47> update test set sid=999 where id =1;
Query OK, 0 rows affected (0.00 sec)
Rows matched: 1 Changed: 0 Warnings: 0
root@localhost : (none) 05:20:03> show engine innodb status\Gshow master status\G
…
—
LOG
—
Log sequence number 12094504
Log flushed up to 12094504
Pages flushed up to 12094504
Last checkpoint at 12094495
0 pending log flushes, 0 pending chkp writes
56 log i/o’s done, 0.00 log i/o’s/second
*************************** 1. row ***************************
File: mysql-bin.000001
Position: 438
Binlog_Do_DB:
Binlog_Ignore_DB:
Executed_Gtid_Set: 8392d215-4928-11e9-a751-0242ac110002:1
1 row in set (0.00 sec)
root@localhost : test 05:19:33> select * from test where id =1;
+—-+——+——+——+
| id | sid | mid | name |
+—-+——+——+——+
| 1 | 999 | 871 | NW |
+—-+——+——+——+
1 row in set (0.00 sec)
root@localhost : test 05:20:44> commit;
Query OK, 0 rows affected (0.01 sec)
root@localhost : test 05:20:57> select * from test where id =1;
+—-+——+——+——+
| id | sid | mid | name |
+—-+——+——+——+
| 1 | 999 | 871 | NW |
+—-+——+——+——+
1 row in set (0.00 sec)
总结
在 binlog_format=statement 和 binlog_row_image=FULL 时,InnoDB 内部认真执行了 update 语句,即“把这个值修改成 (1,999)“这个操作,该加锁的加锁,该更新的更新。
一站式开发者服务,海量学习资源 0 元起!
阿里热门开源项目、机器学习干货、开发者课程 / 工具、小微项目、移动研发等海量资源;更有开发者福利 Kindle、技术图书幸运抽奖,100% 中 –》https://www.aliyun.com/acts/product-section-2019/developer?utm_content=g_1000047140
本文作者:powdba 阅读原文
本文为云栖社区原创内容,未经允许不得转载。