写点什么

MySQL:如果被更新字段的新值与旧值相等,SQL 会被真正执行吗?

作者:程序员拾山
  • 2023-01-20
    河南
  • 本文字数:1431 字

    阅读完需:约 5 分钟

1,问题


有朋友问我一个有趣的问题:当 MySQL 更新一条数据时,如果碰巧被更新字段的新值与原来的值相等,那 MySQL 会“智能”的不执行这条 sql 直接返回成功吗?还是老老实实地把这条 sql 执行一遍呢?

2,猜测


基于以上问题,我想到三个可能的答案:


猜想答案 1:MySQL 的 Server 读出此条数据,发现被更新的字段值并没有发生变化,于是直接返回了成功。


猜想答案 2:MySQL 调用了 InnoDB 引擎,但是引擎发现字段值没有发生变化,于是没有更新数据,而是直接返回结果。


猜想答案 3:MySQL 调用了 InnoDB 引擎,引擎按正常的流程,该加锁就加锁,该更新就更新,最后返回结果。

3,验证


带着问题和思考,咱们实际动手验证一下,到底哪个猜想才是正确的?或者以上猜想都是错误的?


首先,用于测试的 MySQL 版本为 5.7.38,binlog_format 格式为 statement。


新建一张表 test,并插入一条数据


CREATE TABLE test  (  `id` int(11) NOT NULL AUTO_INCREMENT,  `num` int(11) NULL DEFAULT NULL,  PRIMARY KEY (`id`) USING BTREE) ENGINE = InnoDB ;INSERT test(id,num) VALUES(1,2);
复制代码


对于猜想答案 1,我们使用反证法,即如果数据没有被更新,那么两个事务同时更新一条记录,应该互不影响。


我们开启两个事务执行同样的更新 sql,第一个事务关闭事务的默认提交,执行一条更新 sql,并且不提交事务。


然后观察第二个事务中 sql 的执行情况。



如上图所示,如果第一个事务不提交,则第二个事务一直被阻塞,直至事务超时回滚。


很明显,这条数据被加了锁,而加锁是 InnoDB 引擎才能做的事,所以,猜想 1 是错误的,可以排除了。


我们现在知道 MySQL 调用了 InnoDB 引擎,那么 InnoDB 执行了更新操作吗?


我们继续验证猜想答案 2。


对于猜想答案 2,我们使用 MySQL 的视图一致性特性来验证。



如上图所示。开启两个事务,其中事务 A 开启手动提交。


首先我们要知道的是,更新就是在一条数据上加上 trx 的事务版本号。


事务 A 启动后生成了 mvcc 一致性视图,第一个 select 返回的结果是(1,3),


然后事务 B 更新了 num 的值为 4,


事务 A 进行数据更新,此时事务 A 的 update 为当前读,


事务 A 的第二个 select 返回的结果是(1,4)。


由于事务的隔离性,第二个 select 看不到 sessionB 的结果,但是结果是(1,4),只能说明事务 A 的 update 得到了执行,生成了新的版本,才得到了这个结果。


如果没有执行,第二个 select 无法读到 sessionB 中的结果,返回的结果应该是(1,3)。


所以第二个猜想也被否定了。


结合以上实践,猜想答案 3 可以确定是正确的结果。


即,MySQL 更新一条语句时,即使要更新的值与记录中的旧值一样,MySQL 一样会按部就班的执行这条语句。


到这里有的小伙伴可能会问了:MySQL 为什么不做一下优化呢?


其实 MySQL 是做了优化的。


朋友们看下面这条 sql:


update test set num=4 where id=1 and num=4;
复制代码


如果按照上面的步骤进行验证,你会发现 sessionA 的第二个 select 返回的结果会是(1,3)。


是不是有点疑惑?


其实答案也很简单:


MySQL 执行 update 时,如果可以在语句中明确知道要更新的值没有发生变化(where 和 set 中 num 的值是一样的),这条 sql 就会被优化,SHOW ENGINE INNODB STATUS 的 LSN 可以证明这一点,其他情况 MySQL 会按正常的流程执行 sql。

4,最后


这个问题可能对我们平时做功能开发并没有多少帮助,但是深入了解其中的原理,可以让我们更好的理解 MySQL 的执行流程,知其然更知其所以然,与朋友同事吹牛 X 时也更有底气不是。


如果您坚持看到结尾这里,不妨动手实践一下,文中的 binlog_format 格式为 statement,如果改成 row,执行结果又有什么变化?


finally,朋友们点赞关注支持一下吧。

发布于: 刚刚阅读数: 4
用户头像

JAVA技术分享,全网同名 2019-06-19 加入

学习如逆水行舟,不进则退

评论

发布
暂无评论
MySQL:如果被更新字段的新值与旧值相等,SQL会被真正执行吗?_MySQL_程序员拾山_InfoQ写作社区