物化视图的PCT特性(一)
上一篇 / 下一篇 2005-03-12 00:00:00 / 个人分类:ORACLE
Oracle的物化视图从9i开始支持了PARTITION CHANGE TRACKING(PCT)功能。本文简单描述一下PCT的概念及PCT的优点。
物化视图的PCT特性(二):http://blog.itpub.net/post/468/21639
ITPUB个人空间I(ZO8LpQ7W
PCT是基于分区的修改跟踪,如果基表进行了分区,Oracle可以知道物化视图中的每条记录会被基表中的哪个或哪几个分区所影响。
PCT带来的优点主要体现在两个方面上:刷新和查询重新。
当基表发生DROP PARTITION或TRUNCATE PARTITION操作后,物化视图仍然可以执行快速刷新。而且即使不执行快速刷新,Oracle也不会将这个物化视图中所有记录的状态都设置为STALE,只有被分区操作影响的记录变为STALE,其他记录的状态仍然是FRESH,也就是说即使QUERY_REWRITE_INTEGRITY的值设置为ENFORCED或TRUSTED,这时的物化视图也可以部分的提供查询重新,只有那些受到分区影响的记录不再支持查询重新。
下面看个简单的例子:
SQL> conn yangtk/yangtk@test4ITPUB个人空间&v:e
cqI
已连接。
4\@\F9RC Vdg0SQL> show parameter query_rewrite
NAME TYPE VALUE
8}^DB%L`i0------------------------------------ ----------- ---------------------
V9~%\J
U0query_rewrite_enabled string TRUEITPUB个人空间iV~&s JOn
query_rewrite_integrity string enforced
首先看一下运行的环境变量,允许查询重新,query_rewrite_integrity的值是enforced。
下面建立测试所需的例子:
SQL> create table t (id number, time date)
E7mj
I9Z^/?I0 2 partition by range (time)
/Nv4z
B-K6x4?%v,M0 3 (partition p1 values less than (to_date('2004-1-1', 'yyyy-mm-dd')),
a7n*osN0].C0 4 partition p2 values less than (to_date('2005-1-1', 'yyyy-mm-dd')), ITPUB个人空间x
n
yA/[;Z
5 partition p3 values less than (to_date('2006-1-1', 'yyyy-mm-dd')))
ba
^V)}{8G0 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) ITPUB个人空间 a5@ p!gu
y"X'j
2 including new values;
实体化视图日志已创建。
SQL> create materialized view mv_t refresh fast enable query rewrite as ITPUB个人空间9\0Ky)@6R.r6@gJ
2 select time, count(*) from t group by time;
实体化视图已创建。
大致看一下数据的分布。
SQL> select count(*) from t partition(p1);
COUNT(*)
k
bQ"N.DvMA0----------ITPUB个人空间q YA)v:q-@
5840
SQL> select count(*) from t partition(p2);
COUNT(*)
NE1v1yf$^0----------
k6zw"pSpD4h0 366
SQL> select count(*) from t partition(p3);
COUNT(*)
8c
fXt;E0----------
g5wR7E0^0 70
SQL> set autot on expITPUB个人空间s%N)_?4nq;kJ'i
SQL> select time, count(*) from t where time > to_date('2005-1-1', 'yyyy-mm-dd')
Jpe+K{*n7K?
AuW0 2 and time < to_date('2005-1-10', 'yyyy-mm-dd') group by time;
TIME COUNT(*)ITPUB个人空间2J?Ark_(`:|!_
---------- ----------ITPUB个人空间WwQ
m E/rJ
V3R"A
g
01-1月 -05 1
"_Y-|`%mWa$KIk002-1月 -05 1ITPUB个人空间oB k(O-e.rv#C%X
03-1月 -05 1ITPUB个人空间Y#ussr:Y
04-1月 -05 1ITPUB个人空间6r'v"^
h*A}'ij
05-1月 -05 1
n Z-YH-v:A.D/U#K006-1月 -05 1
L;v?9moQyH9h-]007-1月 -05 1ITPUB个人空间&uzbl&p1yZ:JML
08-1月 -05 1
c5~V#H1q_wq009-1月 -05 1
已选择9行。
{ v S#Q\!o|0Execution PlanITPUB个人空间*s5}
sC/MF#i,X
----------------------------------------------------------ITPUB个人空间3fzr.o
K
N
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=3 Card=4 Bytes=88)
+y:CE+}jv0 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')ITPUB个人空间Zrb.V7@)wD3`
2 and time < to_date('2005-1-10', 'yyyy-mm-dd') group by time;
TIME COUNT(*)
b H_@l5Q`R,Xf0---------- ----------ITPUB个人空间p$xf&~JC3U6@/a_"L
01-1月 -05 1
6R7W"b8Eg-I002-1月 -05 1
]aU2V7X(?$M5[003-1月 -05 1
)m|p)uJ:ex0q)Ep"j004-1月 -05 1ITPUB个人空间:d+d
w"X5@9c$W%\M
05-1月 -05 1
2^ R6G_g
X006-1月 -05 1ITPUB个人空间8UaDWg
07-1月 -05 1
OLR^&X UQ\008-1月 -05 1ITPUB个人空间2k]&x6N7]ZLC,_
09-1月 -05 1
已选择9行。
ITPUB个人空间"s l0g%K`kg0I
Execution Plan
7^Vv+E6B/bu(u0----------------------------------------------------------ITPUB个人空间!^$IL
fP
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=3 Card=1 Bytes=22)ITPUB个人空间:t%_/JbzR9N@ m
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')
#I+m3p
wq.o l+R&i1NP.G0 2 and time < to_date('2005-1-10', 'yyyy-mm-dd') group by time;
未选定行
ITPUB个人空间S m/{R&JszcO
Execution PlanITPUB个人空间?ul5YJ.a!x"w
----------------------------------------------------------ITPUB个人空间l
o,^-b3Q
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=3 Card=1 Bytes=22)ITPUB个人空间0I%J8On)v$nwJ
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(*)ITPUB个人空间0C6\nx3IC&^3R
[
----------
e&i{Acf)OH"}(]0 436
9eN,_/`&xL0Execution PlanITPUB个人空间+T8p L4k'ku?u v
----------------------------------------------------------ITPUB个人空间8I@7g'd)mP#U\o^
0 SELECT STATEMENT Optimizer=CHOOSE