作为刚入职的新人,我及时响应了顾问在群内发起的请求:更新某条数据的特定字段值。
- 检查相关业务逻辑
- 定位到对应的业务表
- 执行UPDATE语句
- 结果却显示:Affected rows: 0
咦!没有记录被影响,难道是SQL写错了?再次检查数据,发现字段值的确已经更新过了。原来是客户方的IT同事已经先行处理。此刻内心只能暗叹一句。
这不禁让人疑惑:Affected rows: 0 的出现,难道意味着UPDATE操作在底层真的会先进行比较?这岂不是“脱裤子放屁”,多此一举?更值得深思的是,先比较再更新,会不会影响执行效率?
哈哈!我这十年苦练,终于等到出人头地的机会了?干脆重写底层,直接梭哈...优化代码,走上人生巅峰!等等!这么好的事,轮得到我吗(不禁忆起十年前的电信诈骗故事)?压了口杯中的冷茶,让自己冷静下来,还是仔细翻阅资料为妙。
MySQL在执行UPDATE操作时,确实会在内部进行数据比较。如果发现待更新的新值与记录中的旧值完全相同,在绝大多数情况下,它会优化掉这次不必要的物理写入操作,直接返回成功,并报告Affected rows: 0。
水落石出后,如同拨开云雾见青天。让我们来具体看看这个 比较后跳过机制 是如何工作的。
- 定位记录与获取旧值
数据库引擎会基于WHERE条件(例如使用索引或全表扫描)定位到目标记录,我们可以将其视为 record[1](即旧值记录)。
- 构建新记录数据
执行器根据SET子句中的赋值表达式,构建出新的记录数据 record[0]。
- 关键比较步骤
在服务器层,MySQL会逐字段比对record[0](新值)和record[1](旧值)的二进制内容。
- 判断与终止
如果所有字段的二进制内容都完全一致,系统便判定此次更新未产生任何实际的数据变更。于是,整个更新流程会在此处提前终止。
一个典型的UPDATE语句示例如下:
UPDATE user_salary_mager
SET salary=1000
WHERE name = ucoding
接着划重点:提前终止更新流程,带来了显著的性能好处。存储引擎因此不需要进行以下一系列耗时操作:
- 不需要:加锁
- 不需要:写Undo Log
- 不需要:修改数据页
- 不需要:写Redo Log
这的确是提高性能最优的选择之一了。不过,技术也应该有温度啊!老板,涨工资!老板,涨工资!

对数据库底层机制和性能优化感兴趣?欢迎在云栈社区与更多开发者交流探讨。
|