曾经碰到有开发人员问到,如果一个update语句,更新列的当前值与旧值一致时,数据库是不是直接跳过更新操作,不会重复去做更新替换旧值的操作?
先插播个广告,近期我们正在招DBA,如果您现在知道怎么去印证这个update的问题,而且您准备跳槽的话,请您把简历发我,直接找我们Boss谈薪吧
言归正传,带着这个问题,我将通过以下实验,去逐步解开这个疑问。
案例的实验环境数据库版本11.2.0.1(在内网11.2.0.4和19.6版也同步测过)。测试开启两个会话,Session 1是oramon用户,Session 2是sys用户:
1)在Session 1窗口,创建b2c_users表,插入1行记录,并提交。

2)在Session 2窗口,手工触发检查点,并切换新日志,目的是方便后面分析。

3)在Session 2窗口,查看日志信息,当前日志序号332,有两个成员。

4)在Session 1窗口,查到user_id=1000的user_name为Harion,接着发出update语句,把user_name更新为原先的值Harion,并提交。

5)在Session 2窗口,进行日志切换,并dump下日志序号为332的logfile。

6)在Session 1窗口,查看user_id=1000的记录,落在4号数据文件,块号为4565。表的对象ID为79434。同时,我们将user_name为Harion,dump成16进制,值为0x486172696f6e。

7)接着,我们分析dump下来的日志,通过object_id为79343,在日志里面搜索。找到对应的redo record,它包含了4个改变矢量(change vectors)。其中CHANGE #1,对应的OP是11.19(Array Update ?),可以看到下面红框中第二列,即col 1,实际存储字符长度为6,对应的变更后的值是0x486172696f6e,即为Harion。
CHANGE #2,对应的OP是5.2,即get undo header,从uba可以看到对应undo block address的地址信息。
CHANGE #3,对应的OP是5.4,即rollback or commit操作。

8)CHANGE #4,对应的OP是5.1,即update undo block操作。其中xid对应事务ID,objn对应对象ID,而最下方红框col 1,是update的前镜像,值为0x486172696f6e,即为Harion。

小结:从上面的例子,我们可以看到,就是update列的旧值与当前值是一致的,但数据库还是会去更新原先的值,同时也会生成undo信息。我们从redo的日志可以很清楚看到这个update的处理过程。
这个案例告一个段落,但从这个案例可以引申出另一个问题,如果表里面有索引,且索引字段又是更新列,当前值与旧值不一致时,会有什么不一样?索引的处理逻辑又是什么?下一篇文章将揭晓这个问题。还是那句广告,想到这问题的答案时,您如果准备跳槽的,简历转下我,您直接跟我们Boss聊哈




