暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Mysql中update修改的内容与原数据一致,update会执行吗?

扫地僧的故事 2020-07-28
6600
前几天,一研发小哥突然给我发了个微信,神神秘秘的问我,你觉得这个update会更新几条?(哎,讲话是真的太糙了,原本斯斯文文的我,就是被他们带偏的。。)task_id=1的有4条,那update更新的就是4条呗,这有什么好猜的?

用脚后跟想,也能猜到结果肯定不是4条,答案是只更新了1行记录。不然写这篇文章真的是多此一举了,哈哈哈)
赶紧找个数据库测一下:

居然真的当update修改的内容和原数据一致就不执行了?
那肯定要继续百度看看啦!

天啊,明明我也全部看完了45讲,怎么能一点印象都没有呢,真的是黄鱼脑子啊!
又去翻了翻丁奇45讲(强烈推荐),这道题是第15讲的课后问题。

Oracle肯定是第三种认真执行了“把这个值修改成(1,2)"这个操作,该加锁的加锁,该更新的更新。
Mysql则会根据binlog_format和binlog_row_image参数的不同,而有不同的执行方式。(先把答案告诉大家吧)
首先第一个选项,MySQL 读出数据,发现值与原来相同,不更新,直接返回,执行结束。通过下面这个实验来排除(所有例子都是基于rr隔离级别的):
Session 1:

Session 2:

不管binlog_format是什么格式,Session 2的update都会被blocked了,加锁这个动作,是innodb才能做的,所以能肯定排除了第一个选项。
第二个选项,MySQL 调用了 InnoDB 引擎提供的接口,但是引擎发现值与原来相同,不更新,直接返回。在binlog_format=row和binlog_row_image=FULL时,由于Mysql需要在binlog里面记录所有的字段,所以在读数据的时候就会把所有数据都读出来,那么重复数据的update不会执行。
做个小实验:
Session 1:

Session 2:

Session 1:

第三个选项,InnoDB 认真执行了“把这个值修改成 (1,2)"这个操作,该加锁的加锁,该更新的更新。在binlog_foramt=statement和binlog_row_image=FULL时,InnoDB内部会认真执行了update语句。
丁奇45讲中的两个例子(我就偷懒了,不动手做了)

session A的第2个select语句是一致性读,它是不能看到Session B的更新的,现在它返回(1,3),表示它看见了某个新的版本,这个版本只能是session A自己的update语句做更新的时候生成的。InnoDB 认真执行了“把这个值修改成 (1,2)"这个操作,该加锁的加锁,该更新的更新。

我们可能会觉得为什么MySQL 怎么这么笨,就不会更新前判断一下值是不是相同吗?如果判断一下,不就不用浪费 InnoDB 操作,多去更新一次了?其实 MySQL 是确认了的。只是在这个语句里面,MySQL 认为读出来的值,只有一个确定的 (id=1), 而要写的是 (a=3),只从这两个信息是看不出来“不需要修改”的。

所以也能明白为什么binlog_format参数不同,同样的update语句,执行的方式却不一样了吧?如果Mysql能确认更新的内容,与原数据是一致的,那么就不更新,直接返回。
总结:

1.在binlog_format=row和binlog_row_image=FULL时,由于Mysql需要在binlog里面记录所有的字段,所以在读数据的时候就会把所有数据都读出来,那么重复数据的update不会执行。即MySQL 调用了 InnoDB 引擎提供的接口,但是引擎发现值与原来相同,不更新,直接返回。

2.在binlog_foramt=statement和binlog_row_image=FULL时,InnoDB内部会认真执行了update语句,该加锁的加锁,该更新的更新。

文章转载自扫地僧的故事,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论