这篇文章主要讨论如何通过修改物化视图日志来同步UPDATE操作。
小议物化视图与基表数据不一致的消除(一):http://yangtingkun.itpub.net/post/468/326751
小议物化视图与基表数据不一致的消除(二):http://yangtingkun.itpub.net/post/468/327727
前面一篇文章描述了如何通过手工修改物化视图日志的方法来实现INSERT和DELETE操作的同步。
也许有人认为有了INSERT和DELETE的方法就不需要UPDATE的方法了,因为只需要在物化视图日志中插入一个DELETE的日志,然后在插入一个INSERT对应的日志信息,Oracle在刷新物化视图的时候,就会将需要UPDATE的记录先删除,然后重新插入。
但是,事情并不那么简单。物化视图的刷新并不仅仅依赖于物化视图日志中的内容,事实上,Oracle会根据物化视图和基表的差异来确定是否执行删除和插入的操作。
关于上面的描述可以参考:物化视图刷新并非完全根据物化视图日志记录:http://yangtingkun.itpub.net/post/468/486248
因此想要通过这种手工添加DELETE和INSERT记录的方式来欺骗Oracle是行不通的。UPDATE操作就只能UPDATE的方式来解决。
虽然无法欺骗Oracle,录音DELETE + INSERT的方式来绕过UPDATE操作,但是在UPDATE操作需要更新的列上可以欺骗一下Oracle。
Oracle处于性能的考虑,当表中不包含LOB列时,虽然物化视图日志明确的记录了哪些列需要被更新,但是Oracle并不会将更新细化到列级,而是表中所有的字段全部更新。这样的话,在处理UPDATE语句的时候就有了省事的办法。在物化视图日志表中手工编辑UPDATE记录的时候,可以在列标识的地方输入任意列,比如’02’。这样就可以实现物化视图和基表之前,同一条记录字段数据不同的同步操作。
SQL> exec dbms_mview.refresh('MV_T')
PL/SQL procedure successfully completed.
SQL> select * from t;
ID NAME AGE
---------- ------------------------------ ----------
1 update 18
2 b 26
3 c 34
4 d 40
SQL> select * from mv_t;
ID NAME AGE
---------- ------------------------------ ----------
1 a 18
2 b 26
3 c 34
4 d 40
现在基表和物化视图中ID为1的记录是不同的。现在通过手工添加物化视图日志的方式来实现二者的同步:
SQL> desc mlog$_t
Name Null? Type
----------------------------------- -------- ---------------
ID NUMBER
SNAPTIME$$ DATE
DMLTYPE$$ VARCHAR2(1)
OLD_NEW$$ VARCHAR2(1)
CHANGE_VECTOR$$ RAW(255)
SQL> insert into mlog$_t values (1, to_date('4000-1-1', 'yyyy-mm-dd'), 'U', 'U', '01');
1 row created.
SQL> col change_vector$$ format a10
SQL> select * from mlog$_t;
ID SNAPTIME$$ D O CHANGE_VEC
---------- -------------- - - ----------
1 01-1月 -00 U U 01
SQL> delete t where id = 4;
1 row deleted.
SQL> exec dbms_mview.refresh('MV_T')
PL/SQL procedure successfully completed.
SQL> select * from t;
ID NAME AGE
---------- ------------------------------ ----------
1 update 18
2 b 26
3 c 34
SQL> select * from mv_t;
ID NAME AGE
---------- ------------------------------ ----------
1 update 18
2 b 26
3 c 34
第一个字段表示发生变化的记录的ID。
第二个是时间戳填入4000年1月1日,表示任何物化视图还没有对这个记录进行刷新。
第三个字段表示INSERT/UPDATE/DELETE。
第四个字段表示新值(N)/旧值(O)/修改(U)。
最后一个字段表示修改列的矢量。由于UPDATE的时候会更新所有的非LOB列,因此这里并不需要对应到列上,比如这里插入的’01’实际上指向的是主键列。
关于物化视图日志字段的详细描述可以参考:http://yangtingkun.itpub.net/post/468/20498
关于物化视图是如何利用物化视图日志进行快速刷新的可以参考:http://yangtingkun.itpub.net/post/468/20584
修改MLOG后马上刷新并不会导致数据同步到物化视图,这是由于Oracle在快速刷新的时候发现基表自上次刷新完成后并未发生修改,因此根本没有去读取物化视图日志。
因此在上面的例子中对基表数据进行修改,使得物化视图刷新时,会读取手工添加的物化视图日志信息。
可以看到,通过手工修改物化视图日志的方式,使得Oracle的基表和物化视图日志实现了同步。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/4227/viewspace-613657/ ,如需转载,请注明出处,否则将追究法律责任。