Oracle的物化视图从9i开始支持了PARTITION CHANGE TRACKING(PCT)功能。本文简单描述一下PCT的概念及PCT的优点。
物化视图的PCT特性(二):http://blog.itpub.net/post/468/21639
PCT是基于分区的修改跟踪,如果基表进行了分区,Oracle可以知道物化视图中的每条记录会被基表中的哪个或哪几个分区所影响。
PCT带来的优点主要体现在两个方面上:刷新和查询重新。
当基表发生DROP PARTITION或TRUNCATE PARTITION操作后,物化视图仍然可以执行快速刷新。而且即使不执行快速刷新,Oracle也不会将这个物化视图中所有记录的状态都设置为STALE,只有被分区操作影响的记录变为STALE,其他记录的状态仍然是FRESH,也就是说即使QUERY_REWRITE_INTEGRITY的值设置为ENFORCED或TRUSTED,这时的物化视图也可以部分的提供查询重新,只有那些受到分区影响的记录不再支持查询重新。
下面看个简单的例子:
SQL> conn yangtk/yangtk@test4
已连接。
SQL> show parameter query_rewrite
NAME TYPE VALUE
------------------------------------ ----------- ---------------------
query_rewrite_enabled string TRUE
query_rewrite_integrity string enforced
首先看一下运行的环境变量,允许查询重新,query_rewrite_integrity的值是enforced。
下面建立测试所需的例子:
SQL> create table t (id number, time date)
2 partition by range (time)
3 (partition p1 values less than (to_date('2004-1-1', 'yyyy-mm-dd')),
4 partition p2 values less than (to_date('2005-1-1', 'yyyy-mm-dd')),
5 partition p3 values less than (to_date('2006-1-1', 'yyyy-mm-dd')))
6 ;
IXDBA.NET技术社区表已创建。
SQL> insert into t select rownum, sysdate - rownum from dba_objects;
已创建6276行。
SQL> commit;
提交完成。
SQL> create materialized view log on t with rowid, sequence (id, time)
2 including new values;
实体化视图日志已创建。
SQL> create materialized view mv_t refresh fast enable query rewrite as
2 select time, count(*) from t group by time;
实体化视图已创建。
大致看一下数据的分布。
SQL> select count(*) from t partition(p1);
COUNT(*)
----------
5840
SQL> select count(*) from t partition(p2);
COUNT(*)
----------
366
SQL> select count(*) from t partition(p3);
COUNT(*)
----------
70
SQL> set autot on exp
SQL> select time, count(*) from t where time > to_date('2005-1-1', 'yyyy-mm-dd')
2 and time < to_date('2005-1-10', 'yyyy-mm-dd') group by time;
TIME COUNT(*)
---------- ----------
01-1月 -05 1
02-1月 -05 1
03-1月 -05 1
04-1月 -05 1
05-1月 -05 1
06-1月 -05 1
07-1月 -05 1
08-1月 -05 1
09-1月 -05 1
已选择9行。
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=3 Card=4 Bytes=88)
1 0 TABLE ACCESS (FULL) OF 'MV_T' (Cost=3 Card=4 Bytes=88)
Oracle利用了查询重新机制来返回结果,下面drop掉一个分区,这个分区不影响刚才的那个查询的结果。
SQL> alter table t drop partition p1;
表已更改。
SQL> select time, count(*) from t where time > to_date('2005-1-1', 'yyyy-mm-dd')
2 and time < to_date('2005-1-10', 'yyyy-mm-dd') group by time;
TIME COUNT(*)
---------- ----------
01-1月 -05 1
02-1月 -05 1