在以前的一篇文章中,我介绍过Oracle物化视图日志的结构,里面提到过物化视图日志的CHANGE_VECTOR$$列可以记录表中某一条数据的哪个或哪几个字段发生了变化。也就是说Oracle具备了字段级增量的能力,那么物化视图刷新的时候是否仅仅刷新发生变化的字段,还是物化视图的刷新只能够到达记录集。最近正好有人提出这个问题,那么就顺便探讨一下这个问题。
问题来源:http://www.itpub.net/showthread.php?s=&threadid=623102
物化视图日志结构:http://yangtingkun.itpub.net/post/468/20498
下面先看看piliskys的测试,不过我将测试简化了一点,目的在于更清晰的说明问题。
SQL> CREATE TABLE TT (ID NUMBER PRIMARY KEY, NAME VARCHAR2(30));
表已创建。
SQL> INSERT INTO TT VALUES (1, 'A');
已创建 1 行。
SQL> INSERT INTO TT VALUES (2, 'B');
已创建 1 行。
SQL> INSERT INTO TT VALUES (3, 'C');
已创建 1 行。
SQL> COMMIT;
提交完成。
SQL> CREATE MATERIALIZED VIEW LOG ON TT;
实体化视图日志已创建。
SQL> CREATE MATERIALIZED VIEW MV_TT REFRESH FAST AS SELECT ID FROM TT;
实体化视图已创建。
这个测试的思路是创建一个物化视图MV_TT,物化视图只包含基表TT中的部分列,如果基表TT发生了更新操作,而被更新的字段恰好是物化视图所不需要的字段,那么如果Oracle采用字段级的刷新,则可以忽略物化视图日志上的记录而不进行刷新,如果Oracle采用记录级的刷新,那么针对每条被更新的记录,Oracle都会重新刷新。
这个测试采用的是在物化视图上建立一个基于UPDATE操作的触发器,在触发器中将发生更新操作的记录的ID写到一个日志表中,通过观察日志表中最终结果,判断物化视图对哪些数据进行了更新。
IXDBA.NET社区论坛
SQL> CREATE TABLE LOG_MV_TT (ID NUMBER);
表已创建。
SQL> CREATE OR REPLACE TRIGGER MV_TT BEFORE UPDATE ON MV_TT
2 FOR EACH ROW
3 BEGIN
4 INSERT INTO LOG_MV_TT VALUES (:NEW.ID);
5 END;
6 /
触发器已创建
SQL> UPDATE TT SET NAME = NAME;
已更新3行。
SQL> COMMIT;
提交完成。
SQL> EXEC DBMS_MVIEW.REFRESH('MV_TT')
PL/SQL 过程已成功完成。
SQL> SELECT * FROM LOG_MV_TT;
ID
----------
1
2
3
SQL> COMMIT;
提交完成。
通过测试可以发现,日志表中包含了3条记录,也就是说,物化视图刷新的过程中更新了全部的数据,即使物化视图并没有包含真正被更新的字段。
根据这个测试的结果,Oracle的物化视图的刷新只是到达了记录级,而没有到达字段级。
不过令人疑惑的是,如果是这样的话,那么CHANGE_VECTOR$$列的意义何在呢?难道Oracle不清楚字段级更新的效率会更高吗?难道Oracle记录了各个字段的更新信息是为了以后版本实现字段级刷新而预留的?Oracle真的做不到字段级的刷新吗?(待续)