11.2中物化视图日志可以指定COMMIT SCN,这时物化视图刷新就不需要时间戳了,这篇简单描述Oracle是如何实现通过COMMIT SCN来进行刷新的。

这一篇继续分析Oracle是如何实现快速刷新的。

从上一篇得到的TRACE不难发现,物化视图快速刷新由原来的3条SQL,变成了现在的2条。INSERT和UPDATE语句被合并为一个MERGE语句。

首先来看DELETE语句:

DELETE FROM "TEST"."MV_T" SNAP$

WHERE "ID" IN

(

SELECT DISTINCT LOG$."ID"

FROM

(

 SELECT MLOG$."ID"

 FROM "TEST"."MLOG$_T" MLOG$ ,  ALL_SUMMAP MAP$

 WHERE MLOG$.XID$$ = MAP$.XID

 AND MAP$.COMMIT_SCN > :1

 AND MAP$.COMMIT_SCN <= :2

 AND ("DMLTYPE$$" != 'I')

) LOG$

WHERE (LOG$."ID") NOT IN

(

 SELECT MAS_TAB$."ID"

 FROM "T" "MAS_TAB$"

 WHERE LOG$."ID" = MAS_TAB$."ID"

)

)

/* MV_REFRESH (MRG) */

MERGE INTO "TEST"."MV_T" "SNA$"

USING

(

SELECT CURRENT$."ID",CURRENT$."NAME",CURRENT$."AGE"

FROM

(

 SELECT "T"."ID" "ID","T"."NAME" "NAME","T"."AGE" "AGE"

 FROM "T" "T"

) CURRENT$,

(

 SELECT DISTINCT MLOG$."ID"

 FROM "TEST"."MLOG$_T" MLOG$,  ALL_SUMMAP MAP$

 WHERE MLOG$.XID$$ = MAP$.XID

 AND MAP$.COMMIT_SCN > :1

 AND MAP$.COMMIT_SCN <= :2

 AND ("DMLTYPE$$" != 'D')

) LOG$

WHERE CURRENT$."ID" = LOG$."ID"

)"AV$"

ON ("SNA$"."ID" = "AV$"."ID")

WHEN MATCHED THEN UPDATE

SET "SNA$"."ID" = "AV$"."ID","SNA$"."NAME" = "AV$"."NAME","SNA$"."AGE" = "AV$"."AGE"

WHEN NOT MATCHED THEN INSERT

(SNA$."ID",SNA$."NAME",SNA$."AGE")

VALUES (AV$."ID",AV$."NAME",AV$."AGE")

虽然是3条语句变成了2条,但是从SQL的目的看,和时间戳的物化视图刷新并没有本质的不同。由于不再使用时间戳而改为利用COMMIT SCN,因此Oracle引入了一个辅助表ALL_SUMMAP,通过ALL_SUMMAP将XID转化为对应的SCN。

下面简单看看ALL_SUMMAP的特性:

SQL> SELECT * FROM ALL_SUMMAP;

            XID       COMMIT_SCN

---------------- ----------------

2533498128696031    1112622614013

SQL> SELECT * FROM MLOG$_T;

未选定行

SQL> UPDATE T SET NAME = 'TEST' WHERE ID = 10;

已更新1行。

SQL> COMMIT;

提交完成。

SQL> SELECT * FROM MLOG$_T;

             ID D O CHANGE_VECTOR$$                           XID$$

---------------- - - ------------------------------ ----------------

             10 U U 04                             2814848551361701

SQL> SELECT * FROM ALL_SUMMAP;

            XID       COMMIT_SCN

---------------- ----------------

2814848551361701    1112622655597

2533498128696031    1112622614013

SQL> DELETE T WHERE ID = 10;

已删除1行。

SQL> COMMIT;

提交完成。

SQL> SELECT * FROM ALL_SUMMAP;

            XID       COMMIT_SCN

---------------- ----------------

2814848551361701    1112622655597

1970586829980189    1112622655626

2533498128696031    1112622614013

SQL> SELECT * FROM MLOG$_T;

             ID D O CHANGE_VECTOR$$                           XID$$

---------------- - - ------------------------------ ----------------

             10 U U 04                             2814848551361701

             10 D O 00                             1970586829980189

SQL> EXEC DBMS_MVIEW.REFRESH('MV_T')

PL/SQL过程已成功完成。

SQL> SELECT * FROM ALL_SUMMAP;

            XID       COMMIT_SCN

---------------- ----------------

2814848551361701    1112622655597

1970586829980189    1112622655626

2533498128696031    1112622614013

SQL> CREATE TABLE T_TEST (ID NUMBER PRIMARY KEY);

表已创建。

SQL> CREATE MATERIALIZED VIEW LOG ON T_TEST WITH COMMIT SCN;

实体化视图日志已创建。

SQL> INSERT INTO T_TEST VALUES (1);

已创建1行。

SQL> SELECT * FROM MLOG$_T_TEST;

             ID D O CHANGE_VECTOR$$                           XID$$

---------------- - - ------------------------------ ----------------

              1 I N FE                             2815041824890019

SQL> SELECT * FROM ALL_SUMMAP;

            XID       COMMIT_SCN

---------------- ----------------

2814848551361701    1112622655597

1970586829980189    1112622655626

2533498128696031    1112622614013

SQL> CREATE MATERIALIZED VIEW MV_T_TEST

 2  REFRESH FAST

 3  AS SELECT *    

 4  FROM T_TEST;

实体化视图已创建。

SQL> SELECT * FROM ALL_SUMMAP;

            XID       COMMIT_SCN

---------------- ----------------

2814848551361701    1112622655597

1970586829980189    1112622655626

2815041824890019    1112622655813

2533498128696031    1112622614013

从上面的一系列的测试可以看到,ALL_SUMMAP中的记录对应的是物化视图需要刷新的每个事务。如果没有建立物化视图,只是包含物化视图日志,这时基表的修改不会导致ALL_SUMMAP中新增记录。而每个物化视图需要刷新的每个记录都会在这个表增加一条记录。

因此物化视图刷新的时候只需要刷新SCN大于上次刷新的SCN的修改,就可以确保刷新到最新的状态。

oracle视频教程请关注: