以前写过一篇文章描述物化视图是否进行字段级的刷新。当时得出的结论是包含LOB字段的物化视图会进行字段级的刷新,但是这个结论是在9.2上得出的,最近测试发现,10g上的结果有所不同。
这篇文章研究10g以后版本当LOB对象超过32K时,物化视图如何刷新。
包含LOB的物化视图快速刷新:http://yangtingkun.itpub.net/post/468/493060
包含LOB的物化视图快速刷新(二):http://yangtingkun.itpub.net/post/468/493206
物化视图是否根据字段进行刷新(一):http://yangtingkun.itpub.net/post/468/201236
物化视图是否根据字段进行刷新(二):http://yangtingkun.itpub.net/post/468/201607
物化视图是否根据字段进行刷新(三):http://yangtingkun.itpub.net/post/468/203414
在上面一篇文章中测试发现,在10.2版本中,如果基表的LOB对象超过了4K,或者基表的LOB存储在行外,则物化视图视图刷新的时候对LOB更新了两次,下面将LOB字段的内容增加,使得LOB容量超过VARCHAR2类型的上限32K,再次运行刷新,并建立触发器,检查物化视图刷新时,LOB列被更新的次数。
SQL> SELECT * FROM V$VERSION;
BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.2.0.3.0 - 64bi
PL/SQL Release 10.2.0.3.0 - Production
CORE 10.2.0.3.0 Production
TNS for Linux: Version 10.2.0.3.0 - Production
NLSRTL Version 10.2.0.3.0 - Production
SQL> CREATE TABLE T
2 (
3 ID NUMBER,
4 NAME VARCHAR2(30),
5 CONTENTS CLOB,
6 CONSTRAINT PK_T PRIMARY KEY (ID)
7 );
Table created.
SQL> CREATE MATERIALIZED VIEW LOG ON T;
Materialized view log created.
SQL> CREATE MATERIALIZED VIEW MV_T REFRESH FAST AS
2 SELECT *
3 FROM T;
Materialized view created.
SQL> DECLARE
2 V_LOB CLOB;
3 V_STR VARCHAR2(32767) := RPAD('A', 32767, 'A');
4 BEGIN
5 INSERT INTO T VALUES (1, 'TEST', EMPTY_CLOB) RETURN CONTENTS INTO V_LOB;
6 FOR I IN 1..10 LOOP
7 DBMS_LOB.WRITEAPPEND(V_LOB, LENGTH(V_STR), V_STR);
8 END LOOP;
9 COMMIT;
10 END;
11 /
PL/SQL procedure successfully completed.
SQL> CREATE OR REPLACE TRIGGER TRI_MV_T
2 AFTER INSERT OR UPDATE OR DELETE ON MV_T
3 FOR EACH ROW
4 BEGIN
5 DBMS_OUTPUT.PUT_LINE(DBMS_LOB.GETLENGTH(:NEW.CONTENTS));
6 END;
7 /
Trigger created.
SQL> SET SERVEROUT ON
SQL> EXEC DBMS_MVIEW.REFRESH('MV_T')
327670
PL/SQL procedure successfully completed.
SQL> UPDATE T
2 SET NAME = 'ABC'
3 WHERE ID = 1;
1 row updated.
SQL> COMMIT;
Commit complete.
SQL> EXEC DBMS_MVIEW.REFRESH('MV_T')
327670
PL/SQL procedure successfully completed.
从触发器的工作状态看,物化视图的LOB字段只被更新了一次,即使只更新一次,也意味着10g版本的物化视图的刷新性能要比9.2的差,因为9.2只是根据需要决定是否对物化视图进行刷新。
可是上一篇文章中检查TRACE文件明明看到物化视图的刷新执行了两次,为什么通过触发器的方式发现物化视图仅刷新了一次呢。数据库的测试版本、平台都是相同的,实际上两个测试是在同一个数据库的同一个用户下进行的,除了监测刷新的方法不同之外,唯一的区别就是LOB字段的长度有区别。
记得在第一篇文章的时候使用长度小于4000的字符串测试是,通过SQL_TRACE方式检查,发现物化视图的LOB字段也是只更新了一次。
由于32K正好是VARCHAR2类型和CLOB类型的边界,不会是Oracle处理数据边界的时候出现了重复的情况吧:
SQL> DECLARE
2 V_STR VARCHAR2(32767) := RPAD('A', 32767, 'A');
3 BEGIN
4 INSERT INTO T VALUES (2, 'TEST', V_STR);
5 COMMIT;
6 END;
7 /
PL/SQL procedure successfully completed.
SQL> EXEC DBMS_MVIEW.REFRESH('MV_T')
32767
32767
PL/SQL procedure successfully completed.
SQL> UPDATE T
2 SET NAME = 'ABC'
3 WHERE ID = 2;
1 row updated.
SQL> COMMIT;
Commit complete.
SQL> EXEC DBMS_MVIEW.REFRESH('MV_T')
32767
32767
PL/SQL procedure successfully completed.
SQL> DECLARE
2 V_STR VARCHAR2(32767) := RPAD('A', 32766, 'A');
3 BEGIN
4 INSERT INTO T VALUES (3, 'TEST', V_STR);
5 COMMIT;
6 END;
7 /
PL/SQL procedure successfully completed.
SQL> EXEC DBMS_MVIEW.REFRESH('MV_T')
32766
PL/SQL procedure successfully completed.
果然如此,没想到Oracle居然会出现这种低级的错误,不但对于不需要更新的LOB列进行了更新,而且对于32767长度的LOB类型,居然导致物化视图的LOB列刷新了两次。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/4227/viewspace-619523/ ,如需转载,请注明出处,否则将追究法律责任。