yangtingkun
===========================================================
物化视图的PCT特性(一)
===========================================================

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  ;

表已创建。

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
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=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 Optimizer=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 Optimizer=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 Optimizer=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 Optimizer=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 Optimizer=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 Optimizer=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 Optimizer=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 Optimizer=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 Optimizer=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)

 

yangtingkun 发表于:2005.03.12 21:57 ::分类: ( ORACLE ) ::阅读:(4685次) :: 评论 (18)
[回复]

查询重新 query rewrite 翻译的怪怪的smile

问一下,9i如果,truncate master table的一个partition,仍然可以做fast refresh,那么在snapshot log里面记录的是什么信息那?纪录被删除记录的pid吗?

8i的我一会尝试一下 如果master table是分区的,我truncate/drop/了分区后,是否仍然能做快速刷新?

玉面飞龙 评论于: 2005.03.13 10:59
oracle8.1.7.4 [回复]

SQL> alter table zbmaster drop partition p3;

Table altered.
oracle8i删除分区后 没有记录mlog,无法进行快速刷新

SQL> select count(*) from mlog$_zbmaster;

COUNT(*)
----------
0

SQL> execute dbms_snapshot.refresh('zbsnap','fast');
BEGIN dbms_snapshot.refresh('zbsnap','fast'); END;

*
ERROR at line 1:
ORA-12034: snapshot log on "ORACLE"."ZBMASTER" younger than last refresh
ORA-06512: at "SYS.DBMS_SNAPSHOT", line 617
ORA-06512: at "SYS.DBMS_SNAPSHOT", line 674
ORA-06512: at "SYS.DBMS_SNAPSHOT", line 654
ORA-06512: at line 1

我说单位的一个表1亿条记录也不做分区,原来8i不支持partition ddl后的快速刷新;

玉面飞龙 评论于: 2005.03.13 12:49
[回复]

我记得这时9i的新特性。

物化视图日志中没有额外的变化,应该是通过其他途径实现的。

yangtingkun 评论于: 2005.03.13 13:43
[回复]

我想起来了,PCT要求COMPATIBLE在9.0.0以上。8肯定是不支持的。

yangtingkun 评论于: 2005.03.13 15:57
为什么没有走物化视图 [回复]

SQL> exec P_PARTITION_TOTAL('T');
PARTITION_NAME TOTAL
P1 51077
P2 366
P3 128

PL/SQL procedure successfully completed.

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-01-01 00:00:00', 'yyyy-mm-dd hh24:mi:ss') AND
"TIME"

l1t 评论于: 2006.06.13 16:37
re: 物化视图的PCT特性(一) [回复]

l1t,你没有帖全。如果是论坛上问的那个问题,我已经回复了

yangtingkun 评论于: 2006.06.13 19:59
re: 物化视图的PCT特性(一) [回复]

不好意思啊 删了吧 贴上去没执行计划 唉

寒 评论于: 2010.06.02 13:56
re: 物化视图的PCT特性(一) [回复]

如果要提问去论坛吧,这里的交互不方便,而且SQL容易贴不全

yangtingkun 评论于: 2010.06.02 15:41
re: 物化视图的PCT特性(一) [回复]

杨老师你好,我发到论坛里了。帖子地址:
http://www.itpub.net/viewthread.php?tid=1310260&extra=page%3D1&frombbs=1
先谢了。smile

寒 评论于: 2010.06.03 10:47
re: 物化视图的PCT特性(一) [回复]

已回

yangtingkun 评论于: 2010.06.03 11:26
re: 物化视图的PCT特性(一) [回复]

我刚刚试了一下,还是不行,真怪了

寒 评论于: 2010.06.03 13:23
re: 物化视图的PCT特性(一) [回复]

用提示也不行
除非设置ALTER SESSION SET query_rewrite_integrity='stale_tolerated' 或者 做一次刷新才能启用查询重写

寒 评论于: 2010.06.03 14:52
re: 物化视图的PCT特性(一) [回复]

用你的方法就可以了,和统计信息收集也没关系。可能和删除的数据和查询条件有关系吧。 但是前提得加个REWRITE提示 否则也是全表扫描

寒 评论于: 2010.06.03 16:14
re: 物化视图的PCT特性(一) [回复]

杨老师 找到原因了
where time > '2007-1-1' and time to_date('2007-1-1', 'yyyy-mm-dd') and time '2007-1-1 00:00:00' and time

寒 评论于: 2010.06.03 16:36
re: 物化视图的PCT特性(一) [回复]

晕死 怎么回复又不完全 我发到论坛里吧

整了一天了 laughing

3Q

寒 评论于: 2010.06.03 16:38
re: 物化视图的PCT特性(一) [回复]

有问题还是论坛说吧

yangtingkun 评论于: 2010.06.03 18:25
re: 物化视图的PCT特性(一) [回复]

我今天在10204版本上测试了,结果发现语句也是不走物化视图
(MV_T,需要加提示/*+ REWRITE */才会走MV),再一看,发现是
因为走MV执行计划的COST比走原表的COST大,之后再SET AUTOT
TRACE EXP STAT,发现MV的逻辑读的个数确实是比原表的多。

ZALBB 评论于: 2010.06.08 15:38
re: 物化视图的PCT特性(一) [回复]

访问物化视图比原表慢也是很正常的,说明Oracle还算是比较智能的

yangtingkun 评论于: 2010.06.08 18:15

发表评论
标题

在此添加评论
表情符号: smile laughing tongue angry crying sad wassat wink

称呼

邮箱地址(可选)

个人主页(可选)

 authimage


切换风格
新闻聚合
博客日历
文章归档...
最新发表...
最新评论...
最多阅读文章...
最多评论文章...
博客统计...
Blog信息
网站链接...