Oracle的物化视图从9i开始支持了PARTITION CHANGE TRACKING(PCT)功能。
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 ;
表已创建。
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 ptimizer=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
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 ptimizer=CHOOSE (Cost=3 Card=1 Bytes=22)
1 0 TABLE ACCESS (FULL) OF 'MV_T' (Cost=3 Card=1 Bytes=22)
可以看到,Oracle知道当前查询的数据不会被drop partition的操作所影响,因此仍然选择使用查询重写来返回结果。
SQL> exec dbms_mview.refresh('mv_t')
PL/SQL 过程已成功完成。
Drop分区后,物化视图仍然支持快速刷新。
SQL> alter table t truncate partition p3;
表已截掉。
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;
未选定行
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT ptimizer=CHOOSE (Cost=3 Card=1 Bytes=22)
1 0 TABLE ACCESS (FULL) OF 'MV_T' (Cost=3 Card=1 Bytes=22)
这里的结果似乎有些奇怪,Oracle知道分区P3已经执行了TRUNCATE操作,而且我们查询的数据就是属于P3,为什么还使用查询重写功能呢。不过Oracle返回的结果是正确的。
SQL> select count(*) from mv_t;
COUNT(*)
----------
436
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT ptimizer=CHOOSE
1 0 SORT (AGGREGATE)
2 1 TABLE ACCESS (FULL) OF 'MV_T'
SQL> exec dbms_mview.refresh('mv_t')
PL/SQL 过程已成功完成。
SQL> select count(*) from mv_t;
COUNT(*)
----------
366
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT ptimizer=CHOOSE
1 0 SORT (AGGREGATE)
2 1 TABLE ACCESS (FULL) OF 'MV_T'
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;
未选定行
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT ptimizer=CHOOSE (Cost=3 Card=4 Bytes=88)
1 0 TABLE ACCESS (FULL) OF 'MV_T' (Cost=3 Card=4 Bytes=88)
在快速刷新物化视图MV_T之前,物化视图上仍然保存着分区P3上的数据,虽然Oracle选择了查询重写,但是Oracle并不是仅仅根据MV_T上的信息而返回一个错误的答案,而是根据T执行了TRUNCATE PARTITION P3这个操作,而直接返回当前的查询结果“未选定行”。
PCT对于DML同样有效,但是如果查询的记录和DML修改的记录处于同一个分区中,则不会使用查询重写。
SQL> drop table t;
表已丢弃。
SQL> drop materialized view mv_t;
实体化视图已删除。
SQL> set autot off
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 ;
表已创建。
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> 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 ptimizer=CHOOSE (Cost=3 Card=4 Bytes=88)
1 0 TABLE ACCESS (FULL) OF 'MV_T' (Cost=3 Card=4 Bytes=88)
SQL> delete t where time < to_date('2004-1-1', 'yyyy-mm-dd');
已删除5840行。
Execution Plan
----------------------------------------------------------
0 DELETE STATEMENT ptimizer=CHOOSE (Cost=4 Card=82 Bytes=738)
1 0 DELETE OF 'T'
2 1 TABLE ACCESS (FULL) OF 'T' (Cost=4 Card=82 Bytes=738)
SQL> commit;
提交完成。
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 ptimizer=CHOOSE (Cost=3 Card=4 Bytes=88)
1 0 TABLE ACCESS (FULL) OF 'MV_T' (Cost=3 Card=4 Bytes=88)
SQL> delete t where time > to_date('2005-1-11', 'yyyy-mm-dd');
已删除60行。
Execution Plan
----------------------------------------------------------
0 DELETE STATEMENT ptimizer=CHOOSE (Cost=2 Card=20 Bytes=180)
1 0 DELETE OF 'T'
2 1 TABLE ACCESS (FULL) OF 'T' (Cost=2 Card=20 Bytes=180)
SQL> commit;
提交完成。
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 ptimizer=CHOOSE (Cost=4 Card=1 Bytes=9)
1 0 SORT (GROUP BY) (Cost=4 Card=1 Bytes=9)
2 1 TABLE ACCESS (FULL) OF 'T' (Cost=2 Card=1 Bytes=9)
PCT的限制
物化视图的分区变化跟踪特性(PCT)具有以下的限制条件:
1.物化视图参考的基表中至少有一个是分区的;
2.分区表必须是范围分区或复合分区;
3.分区键必须由单列组成;
4.物化视图必须包含基表的分区列或分区标志;
5.如果物化视图包含GROUP BY语句,则分区列或分区标志必须出现在GROUP BY语句中;
6.数据修改只能发生在分区表中;
7.兼容性设置COMPATIBLE必须在9.0.0.0.0以上;
8.物化视图不能参考远端表、视图或外连接;
9.包含UNION ALL的物化视图不支持基于PCT的刷新。
1.物化视图参考的基表中至少有一个是分区的;
这一点是显而易见的,不过出于科学的态度,还是让事实来说话。
SQL> create table t (id number, time date);
表已创建。
SQL> insert into t select rownum, sysdate - rownum from dba_objects;
已创建6275行。
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> exec dbms_mview.explain_mview('mv_t');
PL/SQL 过程已成功完成。
SQL> col related_text format a4
SQL> col msgtxt format a50
SQL> col capability_name format a16
SQL> select capability_name, possible, related_text, msgtxt
2 from mv_capabilities_table where capability_name like '%PCT%';
CAPABILITY_NAME P RELA MSGTXT
---------------- - ---- ---------------------------------------------
PCT N
PCT_TABLE N T 关系不是一个已分区的表
REFRESH_FAST_PCT N PCT 不可能在实体化视图中的任何从表上
REWRITE_PCT N 无法进行一般重写, 并且 PCT 不可能在任何从表上
2.分区表必须是范围分区或复合分区;
SQL> create table t1 (id number, time date)
2 partition by hash (time)
3 partitions 4;
表已创建。
SQL> insert into t1 select rownum, sysdate - rownum from dba_objects;
已创建6284行。
SQL> commit;
提交完成。
SQL> create materialized view log on t1 with rowid, sequence (id, time)
2 including new values;
实体化视图日志已创建。
SQL> create materialized view mv_t1 refresh fast enable query rewrite as
2 select time, count(*) from t1 group by time;
实体化视图已创建。
SQL> truncate table mv_capabilities_table;
表已截掉。
SQL> exec dbms_mview.explain_mview('mv_t1')
PL/SQL 过程已成功完成。
SQL> select capability_name, possible, related_text, msgtxt
2 from mv_capabilities_table where capability_name like '%PCT%';
CAPABILITY_NAME P RELA MSGTXT
---------------- - ---- ---------------------------------------------
PCT N
PCT_TABLE N T1 PCT 不能与此类分区一起使用
REFRESH_FAST_PCT N PCT 不可能在实体化视图中的任何从表上
REWRITE_PCT N 无法进行一般重写, 并且 PCT 不可能在任何从表上
PCT_TABLE对应的信息很明显,PCT不支持HASH分区,下面看看LIST分区的情况。
SQL> create table t2 (id number, time date)
2 partition by list (time)
3 (partition p1 values (to_date('2004-1-1', 'yyyy-mm-dd')),
4 partition p2 values (to_date('2005-1-1', 'yyyy-mm-dd')));
表已创建。
SQL> insert into t2 select rownum, trunc(sysdate - rownum/24, 'yyyy') from dba_objects;
已创建6291行。
SQL> commit;
提交完成。
SQL> create materialized view log on t2 with rowid, sequence (id, time)
2 including new values;
实体化视图日志已创建。
SQL> create materialized view mv_t2 refresh fast enable query rewrite as
2 select time, count(*) from t2 group by time;
实体化视图已创建。
SQL> truncate table mv_capabilities_table;
表已截掉。
SQL> exec dbms_mview.explain_mview('mv_t2')
PL/SQL 过程已成功完成。
SQL> select capability_name, possible, related_text, msgtxt
2 from mv_capabilities_table where capability_name like '%PCT%';
CAPABILITY_NAME P RELA MSGTXT
---------------- - ---- ---------------------------------------------
PCT N
PCT_TABLE N T2 PCT 不能与此类分区一起使用
REFRESH_FAST_PCT N PCT 不可能在实体化视图中的任何从表上
REWRITE_PCT N 无法进行一般重写, 并且 PCT 不可能在任何从表上
3.分区键必须由单列组成;
SQL> create table t3 (id number, time date)
2 partition by range (id, time)
3 (partition p1 values less than (4000, to_date('2004-1-1', 'yyyy-mm-dd')),
4 partition p2 values less than (4000, to_date('2005-1-1', 'yyyy-mm-dd')),
5 partition p3 values less than (8000, to_date('2004-1-1', 'yyyy-mm-dd')),
6 partition p4 values less than (8000, to_date('2005-1-1', 'yyyy-mm-dd'))
7 )
8 ;
表已创建。
SQL> insert into t3 select rownum, sysdate - rownum from dba_objects;
已创建6281行。
SQL> commit;
提交完成。
SQL> create materialized view log on t3 with rowid, sequence (id, time)
2 including new values;
实体化视图日志已创建。
SQL> create materialized view mv_t3 refresh fast enable query rewrite as
2 select id, time, count(*) from t3 group by id, time;
实体化视图已创建。
SQL> truncate table mv_capabilities_table;
表已截掉。
SQL> exec dbms_mview.explain_mview('mv_t3')
PL/SQL 过程已成功完成。
SQL> select capability_name, possible, related_text, msgtxt
2 from mv_capabilities_table where capability_name like '%PCT%';
CAPABILITY_NAME P RELA MSGTXT
---------------- - ---- ---------------------------------------------
PCT N
PCT_TABLE N T3 PCT 不能与多栏分区关键字一起使用
REFRESH_FAST_PCT N PCT 不可能在实体化视图中的任何从表上
REWRITE_PCT N 无法进行一般重写, 并且 PCT 不可能在任何从表上
4.物化视图必须包含基表的分区列或分区标志;
这点也很容易理解,如果物化视图不包含分区列或分区标志,则Oracle无法知道一条记录会受哪个分区的影响。
SQL> create table t4 (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 ;
表已创建。
SQL> insert into t4 select rownum, sysdate - rownum from dba_objects;
已创建6287行。
SQL> commit;
提交完成。
SQL> create materialized view log on t4 with rowid, sequence (id, time)
2 including new values;
实体化视图日志已创建。
SQL> create materialized view mv_t4 refresh fast enable query rewrite as
2 select id, count(*) from t4 group by id;
实体化视图已创建。
SQL> truncate table mv_capabilities_table;
表已截掉。
SQL> exec dbms_mview.explain_mview('mv_t4')
PL/SQL 过程已成功完成。
SQL> select capability_name, possible, related_text, msgtxt
2 from mv_capabilities_table where capability_name like '%PCT%';
CAPABILITY_NAME P RELA MSGTXT
---------------- - ---- --------------------------------------------
PCT N
PCT_TABLE N T4 在选择列表中缺少分区关键字或 PMARKER
REFRESH_FAST_PCT N PCT 不可能在实体化视图中的任何从表上
REWRITE_PCT N 无法进行一般重写, 并且 PCT 不可能在任何从表上
5.如果物化视图包含GROUP BY语句,则分区列或分区标志必须出现在GROUP BY语句中;
这个条件和上面的类似。
SQL> create materialized view mv_t4 refresh fast enable query rewrite as
2 select id, count(time) from t4 group by id;
实体化视图已创建。
SQL> truncate table mv_capabilities_table;
表已截掉。
SQL> exec dbms_mview.explain_mview('mv_t4')
PL/SQL 过程已成功完成。
SQL> select capability_name, possible, related_text, msgtxt
2 from mv_capabilities_table where capability_name like '%PCT%';
CAPABILITY_NAME P RELA MSGTXT
---------------- - ---- --------------------------------------------
PCT N
PCT_TABLE N T4 在选择列表中缺少分区关键字或 PMARKER
REFRESH_FAST_PCT N PCT 不可能在实体化视图中的任何从表上
REWRITE_PCT N 无法进行一般重写, 并且 PCT 不可能在任何从表上
6.数据修改只能发生在分区表中;
SQL> create table t5 (id number, name varchar2(30));
表已创建。
SQL> insert into t5 select rownum, object_name from dba_objects;
已创建6292行。
SQL> commit;
提交完成。
SQL> create materialized view log on t5 with rowid;
实体化视图日志已创建。
SQL> create materialized view mv_t5 refresh fast enable query rewrite as
2 select a.rowid a_rid, b.rowid b_rid, a.id, a.name, b.time from t5 a, t4 b
3 where a.id = b.id;
实体化视图已创建。
SQL> truncate table mv_capabilities_table;
表已截掉。
SQL> exec dbms_mview.explain_mview('mv_t5')
PL/SQL 过程已成功完成。
SQL> select capability_name, possible, related_text, msgtxt
2 from mv_capabilities_table where capability_name like '%PCT%';
CAPABILITY_NAME P RELA MSGTXT
---------------- - ---- --------------------------------------
PCT Y
PCT_TABLE N T5 关系不是一个已分区的表
PCT_TABLE Y T4
REFRESH_FAST_PCT Y
REWRITE_PCT Y
由于T4是分区表,且满足其他PCT的条件,因此T4是支持PCT的,而T5不是分区表,因此对T5修改将会导致整个物化视图变为STALE状态。
SQL> set autot on exp
SQL> select time, name from t4, t5
2 where t4.id = t5.id
3 and time > to_date('2005-1-1', 'yyyy-mm-dd')
4 and time < to_date('2005-1-3', 'yyyy-mm-dd');
TIME NAME
---------- ------------------------------
02-1月 -05 ALL_MVIEW_AGGREGATES
01-1月 -05 ALL_MVIEW_ANALYSIS
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT ptimizer=CHOOSE (Cost=7 Card=11 Bytes=286)
1 0 TABLE ACCESS (FULL) OF 'MV_T5' (Cost=7 Card=11 Bytes=286)
SQL> delete t4 where time < to_date('2003-12-1', 'yyyy-mm-dd');
已删除5819行。
Execution Plan
----------------------------------------------------------
0 DELETE STATEMENT ptimizer=CHOOSE (Cost=4 Card=82 Bytes=738)
1 0 DELETE OF 'T4'
2 1 TABLE ACCESS (FULL) OF 'T4' (Cost=4 Card=82 Bytes=738)
SQL> commit;
提交完成。
SQL> select time, name from t4, t5
2 where t4.id = t5.id
3 and time > to_date('2005-1-1', 'yyyy-mm-dd')
4 and time < to_date('2005-1-3', 'yyyy-mm-dd');
TIME NAME
---------- ------------------------------
02-1月 -05 ALL_MVIEW_AGGREGATES
01-1月 -05 ALL_MVIEW_ANALYSIS
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT ptimizer=CHOOSE (Cost=7 Card=11 Bytes=286)
1 0 TABLE ACCESS (FULL) OF 'MV_T5' (Cost=7 Card=11 Bytes=286)
SQL> delete t5 where id = 1;
已删除 1 行。
Execution Plan
----------------------------------------------------------
0 DELETE STATEMENT ptimizer=CHOOSE
1 0 DELETE OF 'T5'
2 1 TABLE ACCESS (FULL) OF 'T5'
SQL> commit;
提交完成。
SQL> select time, name from t4, t5
2 where t4.id = t5.id
3 and time > to_date('2005-1-1', 'yyyy-mm-dd')
4 and time < to_date('2005-1-3', 'yyyy-mm-dd');
TIME NAME
---------- ------------------------------
02-1月 -05 ALL_MVIEW_AGGREGATES
01-1月 -05 ALL_MVIEW_ANALYSIS
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT ptimizer=CHOOSE (Cost=7 Card=6 Bytes=312)
1 0 HASH JOIN (Cost=7 Card=6 Bytes=312)
2 1 TABLE ACCESS (FULL) OF 'T4' (Cost=2 Card=1 Bytes=22)
3 1 TABLE ACCESS (FULL) OF 'T5' (Cost=4 Card=2288 Bytes=68640)
7.兼容性设置COMPATIBLE必须在9.0.0.0.0以上;
PCT特性是9i的新特性,9i以下的版本不支持。由于没有8i的环境,没有测试,不过,在上一篇文章的回复中,玉面飞龙做了8174的测试,确认了8i是不支持PCT功能的。
8.物化视图不能参考远端表、视图或外连接;
SQL> alter table t5 add primary key (id);
表已更改。
SQL> create materialized view mv_t6 refresh fast enable query rewrite as
2 select a.rowid a_rid, b.rowid b_rid, a.id, a.name, b.time from t5 a, t4 b
3 where a.id(+) = b.id;
实体化视图已创建。
SQL> truncate table mv_capabilities_table;
表已截掉。
SQL> exec dbms_mview.explain_mview('mv_t6')
PL/SQL 过程已成功完成。
SQL> select capability_name, possible, related_text, msgtxt
2 from mv_capabilities_table where capability_name like '%PCT%';
CAPABILITY_NAME P RELA MSGTXT
---------------- - ---- -------------------------------------------
PCT Y
PCT_TABLE N T5 关系不是一个已分区的表
PCT_TABLE Y T4
REFRESH_FAST_PCT Y
REWRITE_PCT Y
SQL> alter table t4 add primary key (id);
表已更改。
SQL> create materialized view mv_t7 refresh fast enable query rewrite as
2 select a.rowid a_rid, b.rowid b_rid, a.id, a.name, b.time from t5 a, t4 b
3 where a.id = b.id(+);
实体化视图已创建。
SQL> truncate table mv_capabilities_table;
表已截掉。
SQL> exec dbms_mview.explain_mview('mv_t7')
PL/SQL 过程已成功完成。
SQL> select capability_name, possible, related_text, msgtxt
2 from mv_capabilities_table where capability_name like '%PCT%';
CAPABILITY_NAME P RELA MSGTXT
---------------- - ---- ------------------------------------------
PCT Y
PCT_TABLE N T5 关系不是一个已分区的表
PCT_TABLE Y T4
REFRESH_FAST_PCT Y
REWRITE_PCT Y
从上面的测试,没有发现Oracle给出任何错误提示,不过通过测试可以发现,Oracle确实不再支持PCT属性了。
SQL> set autot on exp
SQL> select time, name from t4, t5
2 where t4.id (+) = t5.id
3 and time > to_date('2005-1-1', 'yyyy-mm-dd')
4 and time < to_date('2005-1-3', 'yyyy-mm-dd');
TIME NAME
---------- ------------------------------
02-1月 -05 ALL_MVIEW_ANALYSIS
01-1月 -05 ALL_MVIEW_DETAIL_RELATIONS
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT ptimizer=CHOOSE (Cost=3 Card=6 Bytes=312)
1 0 NESTED LOOPS (Cost=3 Card=6 Bytes=312)
2 1 TABLE ACCESS (FULL) OF 'T4' (Cost=2 Card=1 Bytes=22)
3 1 TABLE ACCESS (BY INDEX ROWID) OF 'T5' (Cost=1 Card=6 Bytes=180)
4 3 INDEX (UNIQUE SCAN) OF 'SYS_C001959' (UNIQUE)
SQL> select time, name from t4, t5
2 where t4.id = t5.id (+)
3 and time > to_date('2005-1-1', 'yyyy-mm-dd')
4 and time < to_date('2005-1-3', 'yyyy-mm-dd');
TIME NAME
---------- ------------------------------
02-1月 -05 ALL_MVIEW_ANALYSIS
01-1月 -05 ALL_MVIEW_DETAIL_RELATIONS
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT ptimizer=CHOOSE (Cost=3 Card=6 Bytes=312)
1 0 NESTED LOOPS (OUTER) (Cost=3 Card=6 Bytes=312)
2 1 TABLE ACCESS (FULL) OF 'T4' (Cost=2 Card=1 Bytes=22)
3 1 TABLE ACCESS (BY INDEX ROWID) OF 'T5' (Cost=1 Card=6 Bytes=180)
4 3 INDEX (UNIQUE SCAN) OF 'SYS_C001959' (UNIQUE)
由于增加了两个主键,Oracle认为现在直接通过基表进行外连接比全表扫描物化视图的代价要小,因此没有选择使用查询重新功能。下面通过HINT:REWRITE来强制使用查询重写功能。
SQL> select /*+ rewrite(mv_t6) */ time, name from t4, t5
2 where t4.id = t5.id (+)
3 and time > to_date('2005-1-1', 'yyyy-mm-dd')
4 and time < to_date('2005-1-3', 'yyyy-mm-dd');
TIME NAME
---------- ------------------------------
02-1月 -05 ALL_MVIEW_ANALYSIS
01-1月 -05 ALL_MVIEW_DETAIL_RELATIONS
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT ptimizer=CHOOSE (Cost=7 Card=11 Bytes=286)
1 0 TABLE ACCESS (FULL) OF 'MV_T6' (Cost=7 Card=11 Bytes=286)
SQL> select /*+ rewrite(mv_t7) */ time, name from t4, t5
2 where t4.id (+) = t5.id
3 and time > to_date('2005-1-1', 'yyyy-mm-dd')
4 and time < to_date('2005-1-3', 'yyyy-mm-dd');
TIME NAME
---------- ------------------------------
02-1月 -05 ALL_MVIEW_ANALYSIS
01-1月 -05 ALL_MVIEW_DETAIL_RELATIONS
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT ptimizer=CHOOSE (Cost=7 Card=11 Bytes=286)
1 0 TABLE ACCESS (FULL) OF 'MV_T7' (Cost=7 Card=11 Bytes=286)
SQL> alter table t4 truncate partition p1;
表已截掉。
SQL> select /*+ rewrite(mv_t6) */ time, name from t4, t5
2 where t4.id = t5.id (+)
3 and time > to_date('2005-1-1', 'yyyy-mm-dd')
4 and time < to_date('2005-1-3', 'yyyy-mm-dd');
TIME NAME
---------- ------------------------------
02-1月 -05 ALL_MVIEW_ANALYSIS
01-1月 -05 ALL_MVIEW_DETAIL_RELATIONS
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT ptimizer=CHOOSE (Cost=3 Card=6 Bytes=312)
1 0 NESTED LOOPS (OUTER) (Cost=3 Card=6 Bytes=312)
2 1 TABLE ACCESS (FULL) OF 'T4' (Cost=2 Card=1 Bytes=22)
3 1 TABLE ACCESS (BY INDEX ROWID) OF 'T5' (Cost=1 Card=6 Bytes=180)
4 3 INDEX (UNIQUE SCAN) OF 'SYS_C001959' (UNIQUE)
SQL> select /*+ rewrite(mv_t7) */ time, name from t4, t5
2 where t4.id (+) = t5.id
3 and time > to_date('2005-1-1', 'yyyy-mm-dd')
4 and time < to_date('2005-1-3', 'yyyy-mm-dd');
TIME NAME
---------- ------------------------------
02-1月 -05 ALL_MVIEW_ANALYSIS
01-1月 -05 ALL_MVIEW_DETAIL_RELATIONS
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT ptimizer=CHOOSE (Cost=3 Card=6 Bytes=312)
1 0 NESTED LOOPS (Cost=3 Card=6 Bytes=312)
2 1 TABLE ACCESS (FULL) OF 'T4' (Cost=2 Card=1 Bytes=22)
3 1 TABLE ACCESS (BY INDEX ROWID) OF 'T5' (Cost=1 Card=6 Bytes=180)
4 3 INDEX (UNIQUE SCAN) OF 'SYS_C001959' (UNIQUE)
可以看到,即使指定了REWRITE,发生分区修改后,PCT功能已经消失,而这正是外关联带来的后果。
SQL> conn yangtk/yangtk@yangtk已连接。
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 ;
表已创建。
SQL> insert into t select rownum, sysdate - rownum from dba_objects;
已创建32259行。
SQL> commit;
提交完成。
SQL> create materialized view log on t with rowid, sequence (id, time)
2 including new values;
实体化视图日志已创建。
SQL> conn yangtk/yangtk@test4
已连接。
SQL> create materialized view mv_t_remote refresh fast enable query rewrite as
2 select time, count(*) from t@yangtk group by time;
实体化视图已创建。
SQL> truncate table mv_capabilities_table;
表已截掉。
SQL> exec dbms_mview.explain_mview('mv_t_remote')
PL/SQL 过程已成功完成。
SQL> select capability_name, possible, related_text, msgtxt
2 from mv_capabilities_table where capability_name like '%PCT%';
CAPABILITY_NAME P RELA MSGTXT
---------------- - ---- -------------------------------------------
PCT N
PCT_TABLE N T 关系不是一个已分区的表
REFRESH_FAST_PCT N PCT 不可能在实体化视图中的任何从表上
REWRITE_PCT N 无法进行一般重写, 并且 PCT 不可能在任何从表上
SQL> select count(*) from mv_t_remote;
COUNT(*)
----------
32259
Oracle无法了解远处表的详细情况,因此不认为远端表是分区表。
SQL> create view v_t5 as
2 select a.rowid a_rid, b.rowid b_rid, a.id, a.name, b.time from t5 a, t4 b
3 where a.id = b.id;
视图已建立。
SQL> create materialized view mv_v_t5 as select * from v_t5;
实体化视图已创建。
SQL> truncate table mv_capabilities_table;
表已截掉。
SQL> exec dbms_mview.explain_mview('mv_v_t5')
PL/SQL 过程已成功完成。
SQL> select capability_name, possible, related_text, msgtxt
2 from mv_capabilities_table where capability_name like '%PCT%';
CAPABILITY_NAME P RELA MSGTXT
---------------- - ---- --------------------------------------------
PCT N
PCT_TABLE N V_T5 关系不是一个已分区的表
REFRESH_FAST_PCT N PCT 不可能在实体化视图中的任何从表上
REWRITE_PCT N 无法进行一般重写, 并且 PCT 不可能在任何从表上
通过视图建立的物化视图不再支持PCT。
9.包含UNION ALL的物化视图不支持基于PCT的刷新。
SQL> create table t8 (id number, time date, num1 number, num2 number)
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 ;
表已创建。
SQL> insert into t8 select rownum, sysdate - rownum,
2 rownum * 2, rownum * 3 from dba_objects;
已创建6298行。
SQL> commit;
提交完成。
SQL> create materialized view log on t8 with rowid, sequence (time, num1, num2)
2 including new values;
实体化视图日志已创建。
SQL> create materialized view mv_t8 refresh fast enable query rewrite as
2 select 1 flag, time, count(*) cnt, count(num1) num_cnt, sum(num1) total
3 from t8 group by time
4 union all
5 select 2 flag, time, count(*) cnt, count(num2) num_cnt, sum(num2) total
6 from t8 group by time;
实体化视图已创建。
SQL> truncate table mv_capabilities_table;
表已截掉。
SQL> exec dbms_mview.explain_mview('mv_t8')
PL/SQL 过程已成功完成。
SQL> select capability_name, possible, related_text, msgtxt
2 from mv_capabilities_table where capability_name like '%PCT%';
CAPABILITY_NAME P RELA MSGTXT
---------------- - ---- --------------------------------------------
PCT Y
PCT_TABLE Y T8
PCT_TABLE N T8 在选择列表中缺少分区关键字或 PMARKER
REFRESH_FAST_PCT Y
REWRITE_PCT N 无法进行一般重写, 并且 PCT 不可能在任何从表上
SQL> alter table t8 drop partition p1;
表已更改。
SQL> exec dbms_mview.refresh('mv_t8');
BEGIN dbms_mview.refresh('mv_t8'); END;
*
ERROR 位于第 1 行:
ORA-32313: PMOP 之后不支持 "YANGTK"."MV_T8" 的 REFRESH FAST
ORA-06512: 在"SYS.DBMS_SNAPSHOT", line 794
ORA-06512: 在"SYS.DBMS_SNAPSHOT", line 851
ORA-06512: 在"SYS.DBMS_SNAPSHOT", line 832
ORA-06512: 在line 1
虽然EXPLAIN_MVIEW给出的解释是支持REFRESH_FAST_PCT的,但是通过测试,发现和文档上描述的一致,包含UNION ALL的物化视图不支持基于PCT的快速刷新。
查询Oracle的ORA-32313错误信息:
ORA-32313 REFRESH FAST of "string"."string" unsupported after PMOPs
Cause: A Partition Maintenance Operation (PMOP) has been performed on a detail table, and the specified materialized view does not support fast refersh after PMOPs.
Action: Use REFRESH COMPLETE. You can determine why your materialized view does not support fast refresh after PMOPs using the DBMS_MVIEW.EXPLAIN_MVIEW() API.
对于EXPLAIN_MVIEW的解释大部分没有问题,但是对于基于外连接的物化视图和包含UNION ALL的物化视图,EXPLAIN_MVIEW的结果有些问题,在使用的时候需要留心。
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/14270146/viewspace-677010/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/14270146/viewspace-677010/