ORACLE物化视图--循序渐进MView(二) MView Log的结构与快速刷新



前言

现在我们通过一些例子来说明一下MView Log的基本结构以及MView快速刷新的过程。

在这一部分里面,我们还是利用上一部分提供的例子先建立一个MView,同时也创建该MView基表的MView Log。

-- 创建一个测试用的表T
USER @ orcl >  create   table   t   ( a   int ,  b   varchar2 ( 50 ) ,  constraint   pk_t primary   key ( a )) ;
Table   created .
 
-- 创建对应的MV名为MVT
USER @ orcl >  create   materialized   view   mvt   as   select  *  from   t ;
Materialized   view   created .
 
-- 现在往表里面插入一些个数据
USER @ orcl >  insert   into   t   select   rownum ,  object_name   from all_objects ;
11449   rows   created .
 
USER @ orcl >  commit ;
Commit   complete .
 
-- 下面对mview做一次刷新看看
USER @ orcl >  exec   dbms_mview . refresh ( ' mvt ' ) ;
PL / SQL   procedure   successfully   completed .
 
-- 创建MView Log
USER @ orcl >  create   materialized   view   log   on   t ;
Materialized   view   log   created .
 
-- 接下来就是进行快速刷新了
USER @ orcl >  exec   dbms_mview . refresh ( ' mvt ' ,  ' F ' ) ;
PL / SQL   procedure   successfully   completed .

 


MView Log的结构

我们先看一下两个测试表的MView Log的结构:

-- 含有PK的MView
USER @ orcl >  desc   mlog $ _t ;
  Name                   Null ?     Type
 ------------------ -- -------- --------------
  A                               NUMBER
  SNAPTIME $$                     DATE
  DMLTYPE $$                      VARCHAR2 ( 1 )
  OLD_NEW $$                      VARCHAR2 ( 1 )
  CHANGE_VECTOR $$                RAW ( 255 )

现在我们挨个说一下各列的含义:

A
这个我们基表T的主键列,如果基表的主键是一个复合索引的话那这里也就存在多个和基表定义一样的列,当基表被修改以后,基表的主键就会被记录到这个列里面。
SNAPTIME$$
用来记录MView刷新的时间,这个字段只有在一个基表对应一个以上的MView的时候才有意义,因为对于一个MView Log来说,只有当所有的MView都刷新完了以后才能把MView Log里面的记录删除,当一个MView刷新的时候,它会把此列置成该MView刷新的时候,在这个MView再次刷新的时候,那些上次刷新过的列就不用再次被刷新了。

下面我们用一个例子来说明一下:

-- 在建立一个基于表T的MView MVT2
USER @ orcl >  create   materialized   view   mvt2   as   select  *  from   t ;
Materialized   view   created .
 
-- 先做一次刷新
USER @ orcl >  exec   dbms_mview . refresh ( ' mvt2 ' ) ;
PL / SQL   procedure   successfully   completed .
 
-- 现在对表T做一些修改
USER @ orcl >  update   t   set   b = upper ( b )   where   rownum < 5 ;
 
4   rows   updated .
 
-- 现在看看MView Log的记录
USER @ orcl >  select  *  from   mlog $ _t ;
 
          A   SNAPTIME $$           D   O   CHANGE_VEC
-------- -- ------------------- - - ----------
        936   4000 - 01 - 01   00 : 00 : 00   U   U   04
        937   4000 - 01 - 01   00 : 00 : 00   U   U   04
        938   4000 - 01 - 01   00 : 00 : 00   U   U   04
        939   4000 - 01 - 01   00 : 00 : 00   U   U   04
 
-- 现在我们刷新MVT
USER @ orcl >  exec   dbms_mview . refresh ( ' mvt ' , ' f ' ) ;
 
PL / SQL   procedure   successfully   completed .
 
-- 我们可以看到SNAPTIME$$时间变了
USER @ orcl >  select  *  from   mlog $ _t ;
 
          A   SNAPTIME $$           D   O   CHANGE_VEC
-------- -- ------------------- - - ----------
        936   2009 - 02 - 18   07 : 28 : 09   U   U   04
        937   2009 - 02 - 18   07 : 28 : 09   U   U   04
        938   2009 - 02 - 18   07 : 28 : 09   U   U   04
        939   2009 - 02 - 18   07 : 28 : 09   U   U   04
 
-- 对比一下MVT的LAST_REFRESH_DATE,我们可以发现这个是一样的
USER @ orcl >  select   MVIEW_NAME ,  LAST_REFRESH_DATE   from   dba_mviews where   mview_name   in   ( ' MVT ' ,  ' MVT2 ' ) ;
 
MVIEW_NAME                       LAST_REFRESH_DATE
---------------------------- -- -------------------
MVT                              2009 - 02 - 18   07 : 28 : 09
MVT2                             2009 - 02 - 18   07 : 27 : 19
DMLTYPE$$
用于表示DML操作类型,I表示INSERT,D表示DELETE,U表示UPDATE,这个我们可以从上面的例子里面得到验证。
OLD_NEW$$
用于表示这个值是新值还是旧值。N(EW)表示新值,O(LD)表示旧值,U表示UPDATE操作。
CHANGE_VECTOR$$
表示修改矢量,用来表示被修改的是哪个或哪几个字段,用二进制的方式来保存修改列的结果。
USER @ orcl >  create   table   ttt   ( a   int ,  b   varchar ( 40 ) ,  c   varchar ( 40 )) ;
 
Table   created .
 
USER @ orcl >  alter   table   ttt   add   constraint   pk_ttt   primary   key ( a ) ;
 
Table   altered .
 
USER @ orcl >  insert   into   ttt   select   rownum ,  object_name ,  object_name from   all_objects ;
 
11488   rows   created .
 
USER @ orcl >  commit ;
 
Commit   complete .
 
USER @ orcl >  create   snapshot   mvttt   as   select  *  from   ttt ;
 
Materialized   view   created .
 
USER @ orcl >  create   snapshot   log   on   ttt ;
 
Materialized   view   log   created .
 
USER @ orcl >  commit ;
 
Commit   complete .
 
USER @ orcl >  update   ttt   set   b = upper ( b )   where   rownum < 5 ;
 
4   rows   updated .
 
USER @ orcl >  update   ttt   set   c = upper ( c )   where   rownum < 5 ;
 
4   rows   updated .
 
USER @ orcl >  update   ttt   set   b = upper ( b ) ,  c = upper ( c )   where   rownum < 5 ;
 
4   rows   updated .
 
USER @ orcl >  select  *  from   mlog $ _ttt ;
 
          A   SNAPTIME $$           D   O   CHANGE_VEC
-------- -- ------------------- - - ----------
        253   4000 - 01 - 01   00 : 00 : 00   U   U   04
        254   4000 - 01 - 01   00 : 00 : 00   U   U   04
        255   4000 - 01 - 01   00 : 00 : 00   U   U   04
        256   4000 - 01 - 01   00 : 00 : 00   U   U   04
        253   4000 - 01 - 01   00 : 00 : 00   U   U   08
        254   4000 - 01 - 01   00 : 00 : 00   U   U   08
        255   4000 - 01 - 01   00 : 00 : 00   U   U   08
        256   4000 - 01 - 01   00 : 00 : 00   U   U   08
        253   4000 - 01 - 01   00 : 00 : 00   U   U   0 C
        254   4000 - 01 - 01   00 : 00 : 00   U   U   0 C
        255   4000 - 01 - 01   00 : 00 : 00   U   U   0 C
        256   4000 - 01 - 01   00 : 00 : 00   U   U   0 C

从上面的例子我们可以看出,修改列B的CHANGE_VECTOR$$是04(0100),修改列C的CHANGE_VECTOR$$值是08(1000),同时修改这两个列就变成了0C(1100)。


刷新的过程


完全刷新的过程

在Oracle 9i以及以前版本中,MView的完全刷新是先对数据库基表做一个truncate操作然后再将基表的数据全部插入到MView中,而Oracle 10g中,MView完全刷新之前并不对MView进行truncate的操作,取而代之的是delete操作,这个在操作大量的数据的时候会有很大的影响,这一点可以通过开trace来看到,这里就不在贴实验的具体过程了。


快速刷新过程

看了MView Log的结构之后我们很容易就能理解MView快速刷新的基本原理了:首先在对基表做update、delete、insert操作之后,隐藏的触发器会把基表的修改记录到MView Log中,在MView Log中基表的主键会被记录(仅对于基于PK的MView来说,其他类型的MView随后介绍),这个记录的pk会在MView做快速刷新的时候被用来定位被操作的数据行,同时还有一些其他的数据会被记录。

在MView做快速刷新的时候,对于不同的操作语句会有一点点不一样的地方:

insert操作
通过MView Log记录的基表的主键数据以及DMLTYPE$$字段我们知道那些行是行是新插入的,只要将这些新数据导入到MView中即可。
delete操作
同样通过MView Log记录的基表的主键数据以及DMLTYPE$$字段我们知道那些行是行是被删除了的,只要将这些在基表被删除掉的数据在MView中删除掉即可。
update操作
通过MView Log记录的基表的主键,DMLTYPE$$字段以及CHANGE_VECTOR$$我们知道那些行的那些列进行了更新的操作,然后再依照基表的数据对MView中相应的列挨个进行刷新操作。

下面我们利用上面的MVTTT进行一下update操作的实验,主要是验证update的时候Oracle是否只会update基表中被修改的列:
首先我们建立一个对MView MVTTT中列C的触发器,在当C列被修改以后在一个新表中插入一条记录。

-- 创建一个记录表
USER @ orcl >  create   table   ttt_t ( a   timestamp   default   sysdate ,  b varchar ( 10 )) ;
Table   created .
 
-- 创建相应的触发器
USER @ orcl >
     CREATE   OR   REPLACE   TRIGGER   tri_mvttt
     BEFORE   INSERT   OR   DELETE   OR   UPDATE   OF   c   ON   ttt
     FOR   EACH   ROW
     BEGIN
         INSERT   INTO   ttt_t   VALUES ( SYSDATE ,  ' c ' ) ;
     END   tri_mvttt ;
    /
 
Trigger   created .

现在我们对基表的列b做一次更新的操作,看看刷新MView以后表TTT_T中是否有数据

USER @ orcl >  update   ttt   set   b = upper ( b )   where   rownum < 5 ;
4   rows   updated .
 
USER @ orcl >  select  *  from   mlog $ _ttt ;
          A   SNAPTIME $$           D   O   CHANGE_VEC
-------- -- ------------------- - - ----------
        253   4000 - 01 - 01   00 : 00 : 00   U   U   04
        254   4000 - 01 - 01   00 : 00 : 00   U   U   04
        255   4000 - 01 - 01   00 : 00 : 00   U   U   04
        256   4000 - 01 - 01   00 : 00 : 00   U   U   04
 
-- 做一次快速刷新
USER @ orcl >  exec   dbms_mview . refresh ( ' mvttt ' ,  ' f ' ) ;
PL / SQL   procedure   successfully   completed .
 
-- 我们可以看到TTT_T里面是没有数据的
USER @ orcl >  select  *  from   ttt_t ;
no   rows   selected

接着我们再对对基表的列c做一次更新的操作,看看刷新MView以后表TTT_T中是否有数据

USER @ orcl >  update   ttt   set   c = upper ( c )   where   rownum < 5 ;
4   rows   updated .
 
USER @ orcl >  select  *  from   mlog $ _ttt ;
          A   SNAPTIME $$           D   O   CHANGE_VEC
-------- -- ------------------- - - ----------
        253   4000 - 01 - 01   00 : 00 : 00   U   U   08
        254   4000 - 01 - 01   00 : 00 : 00   U   U   08
        255   4000 - 01 - 01   00 : 00 : 00   U   U   08
        256   4000 - 01 - 01   00 : 00 : 00   U   U   08
 
-- 做一次快速刷新
USER @ orcl >  exec   dbms_mview . refresh ( ' mvttt ' ,  ' f ' ) ;
PL / SQL   procedure   successfully   completed .
 
-- 这回我们可以看到数据了
USER @ orcl >  select  *  from   ttt_t ;
 
A                                  B
---------------------------- --   ----------
18 - FEB - 09   01.16.53.000000   PM       c
18 - FEB - 09   01.16.53.000000   PM       c
18 - FEB - 09   01.16.53.000000   PM       c
18 - FEB - 09   01.16.53.000000   PM       c

注意:对于基表的每一次update操作都会被记录到MView Log中,不管更新的是否是同一行的同一列,而这些操作也会在MView中被一一的推一遍,一个不拉的,这样如果一个MView操作很频繁而且刷新的间隔太长了的话快速刷新也是很痛苦的一件事的。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值