物化视图是包括一个查询结果的数据库对像,它是远程数据的的本地副本,或者用来生成基于数据表求和的汇总表。物化视图允许在本地维护远程数据的副本。物化视图是单向的,虽然可以更新物化视图的数据,但是一旦刷新后,更新的数据就没有了。高级复制是双向的。
创建自动更新的物化视图
CREATE MATERIALIZED VIEW T_TEST_MV
REFRESH FAST ON DEMAND WITH ROWID
START WITH SYSDATE NEXT SYSDATE + 30/86400
AS
SELECT * FROM t_test;
这样,T_TEST_MV会有一个job自动更新,时间间隔为30秒。
On Demand的话,如果加了START WITH子句,在dba_jobs中有个刷新Job,具体Job ID可以查看dba_refresh、dba_refresh_children视图。如果不加START WITH则需要自己刷新Begin dbms_mview.refresh(list => 'T_TEST_MV', method => 'F');END; 。
第二个参数表示刷新的方式:F-Fast,C-Complete,?-Force
上面创建物化视图的模式为ON DEMAND,还有一种是ON COMMIT,ON DEMAND指物化视图在用户需要的时候进行刷新,可以手工刷新,也可以通过JOB定时进行刷新。ON COMMIT指物化视图在对基表的DML操作提交的同时进行刷新。
刷新的方法有四种:FAST、COMPLETE、FORCE和NEVER。FAST刷新采用增量刷新,只刷新自上次刷新以后进行的修改。COMPLETE刷新对整个物化视图进行完全的刷新。如果选择FORCE方式,则Oracle在刷新时会去判断是否可以进行快速刷新,如果可以则采用FAST方式,否则采用COMPLETE的方式。NEVER指物化视图不进行任何刷新。默认值是FORCE ON DEMAND。
快速刷新需要先创建原表的物化视图日志,先创建一个表T_TEST,然后就可以创建它的物化视图日志。
create materialized view log on T_TEST with rowid;
这样就创建了一个物化视图日志了,通过下面的查询,可以看到日志是否已创建:
Select * From all_mview_logs Where Master = 'T_TEST';
通过下面的查询,可以看到日志的内容:
SELECT * FROM mlog$_T_TEST;
上面那个物化视图是通过with rowid指定为ROWID的,也可以指定PRIMARY KEY,则物化视图日志中会包含主键列。
一个表建立一个物化视图日志,如果原表的数据作了更新,但是对应的物化视图没有刷新,那么物化视图日志里面就会有表更新的相关记录,一旦刷新了,会清除记录。物化视图日志可以对应多个物化视图的刷新,那么只有所有物化视图都刷新了,日志才会清空。
下面作了个测试看在刷新过程中,物化视图日志是怎样起作用的,是怎样刷新多个视图的。
创建表:
create table t_test
(f1 number,
f2 number);
创建日志
create materialized view log on t_test with rowid;
创建2个物化视图
create materialized view t_test_mv refresh fast on demand with rowid as
select * from t_test;
create materialized view t_test_mv2 refresh fast on demand with rowid as select * from t_test;
(如果原表增加了新的字段,物化视图是不能刷新过来的。)
插入数据
insert into t_test values (1,1);
commit;
查看这两个视图的情况
SELECT mview_name,
last_refresh_date,
staleness
FROM all_mviews
WHERE mview_name IN ('T_TEST_MV', 'T_TEST_MV2');
MVIEW_NAME | LAST_REFRESH_DATE |
STALENESS |
T_TEST_MV | 2008-12-17 17:01:00 | NEEDS_COMPILE |
T_TEST_MV2 | 2008-12-17 17:01:02 | NEEDS_COMPILE |
从状态字段可以看出这两个物化视图都需要刷新。
查询物化视图日志
select * from mlog$_t_test
表中有一条记录,SNAPTIME$$的字段为4000-1-1,表示t_test_mv和t_test_mv2都没有刷新。DML类型为“insert”,是新值。
SNAPTIME$$ | DMLTYPE$$ | OLD_NEW$$ | CHANGE_VECTOR$$ |
4000-1-1 | I | N | FE |
SNAPTIME$$:刷新时间。
DMLTYPE$$:DML操作类型,I表示INSERT,D表示DELETE,U表示UPDATE。
OLD_NEW$$:用于表示这个值是新值还是旧值。N(EW)表示新值,O(LD)表示旧值,U表示UPDATE操作。
CHANGE_VECTOR$$:被修改的是哪个或哪几个字段。
刷新t_test_mv,
sys.dbms_snapshot.refresh('t_test_mv');
查看这两个视图的情况
MVIEW_NAME | LAST_REFRESH_DATE |
STALENESS |
T_TEST_MV | 2008-12-17 17:02:36 | FRESH |
T_TEST_MV2 | 2008-12-17 17:01:02 | NEEDS_COMPILE |
T_TEST_MV状态为FRESH,表示已刷新过,而T_TEST_MV2状态为NEEDS_COMPILE,表示还需要刷新。
查询物化视图日志
SNAPTIME$$ | DMLTYPE$$ | OLD_NEW$$ | CHANGE_VECTOR$$ |
2008-12-17 17:02:36 | I | N | FE |
表中记录仍然存在,只是SNAPTIME$$的字段变为刚刚刷新t_test_mv的时间,然后再刷新T_TEST_MV2,日志中的记录被清除。物化视图日志在刷新过程中就是这样记录了多个视图的刷新情况。