文档库 最新最全的文档下载
当前位置:文档库 › 物化视图

物化视图

物化视图的快速刷新要求基本必须建立物化视图日志,这篇文章简单描述一下物化视图日志中各个字段的含义和用途。





物化视图日志的名称为MLOG$_后面跟基表的名称,如果表名的长度超过20位,则只取前20位,当截短后出现名称重复时,Oracle会自动在物化视图日志名称后面加上数字作为序号。

物化视图日志在建立时有多种选项:可以指定为ROWID、PRIMARY KEY和OBJECT ID几种类型,同时还可以指定SEQUENCE或明确指定列名。上面这些情况产生的物化视图日志的结构都不相同。

任何物化视图都会包括的列:

SNAPTIME$$:用于表示刷新时间。

DMLTYPE$$:用于表示DML操作类型,I表示INSERT,D表示DELETE,U表示UPDATE。

OLD_NEW$$:用于表示这个值是新值还是旧值。N(EW)表示新值,O(LD)表示旧值,U表示UPDATE操作。

CHANGE_VECTOR$$表示修改矢量,用来表示被修改的是哪个或哪几个字段。

如果WITH后面跟了ROWID,则物化视图日志中会包含:

M_ROW$$:用来存储发生变化的记录的ROWID。

如果WITH后面跟了PRIMARY KEY,则物化视图日志中会包含主键列。

如果WITH后面跟了OBJECT ID,则物化视图日志中会包含:

SYS_NC_OID$:用来记录每个变化对象的对象ID。

如果WITH后面跟了SEQUENCE,则物化视图日子中会包含:

SEQUENCE$$:给每个操作一个SEQUENCE号,从而保证刷新时按照顺序进行刷新。

如果WITH后面跟了一个或多个COLUMN名称,则物化视图日志中会包含这些列。



下面通过例子进行详细说明:

SQL> create table t_rowid (id number, name varchar2(30), num number);

表已创建。

SQL> create materialized view log on t_rowid with rowid, sequence (name, num) including new values;

实体化视图日志已创建。

SQL> create table t_pk (id number primary key, name varchar2(30), num number);

表已创建。

SQL> create materialized view log on t_pk with primary key;

实体化视图日志已创建。

SQL> create type t_object as object (id number, name varchar2(30), num number);
2 /

类型已创建。

SQL> create table t_oid of t_object;

表已创建。

SQL> create materialized view log on t_oid with object id;

实体化视图日志已创建。

建立环境后来看看物化视图日志中包含的自动:

SQL> desc mlog$_t_rowid
名称 是否为空? 类型
--------------------------------------- -------- -------------
NAME VARCHAR2(30)
NUM NUMBER
M_ROW$$ VARCHAR2(255)
SEQUENCE$$ NUMBER
SNAPTIME$$ DATE
DMLTYPE$$ VARCHAR2(

1)
OLD_NEW$$ VARCHAR2(1)
CHANGE_VECTOR$$ RAW(255)

除了最基本的4列之外,由于指定了ROWID、SEQUENCE和NAME、NUM列,因此物化视图日志中包含了相对应的列。

SQL> desc mlog$_t_pk
名称 是否为空? 类型
----------------------------------------- -------- -------------
ID NUMBER
SNAPTIME$$ DATE
DMLTYPE$$ VARCHAR2(1)
OLD_NEW$$ VARCHAR2(1)
CHANGE_VECTOR$$ RAW(255)

主键物化视图日志中除了基本列之外还包括基本的主键。

SQL> desc mlog$_t_oid
名称 是否为空? 类型
--------------------------------------- -------- -------------
SYS_NC_OID$ RAW(16)
SNAPTIME$$ DATE
DMLTYPE$$ VARCHAR2(1)
OLD_NEW$$ VARCHAR2(1)
CHANGE_VECTOR$$ RAW(255)

对象表的物化视图日志建立后包含系统对象标识列。

一、主键列、ROWID列、OBJECT ID列、SEQUENCE列和建立物化视图时指明的列。

主键、ROWID或OBJECT ID用来唯一表示物化视图日志中的记录。

SEQUENCE会根据操作发生的顺序对物化视图日志中的记录编号。

建立物化视图时指明的列会在物化视图日志中进行记录。

SQL> insert into t_rowid values (1, 'a', 5);

已创建 1 行。

SQL> update t_rowid set name = 'c' where id = 1;

已更新 1 行。

SQL> delete t_rowid;

已删除 1 行。

SQL> select name, num, m_row$$, sequence$$, dmltype$$ from mlog$_t_rowid;

NAME NUM M_ROW$$ SEQUENCE$$ D
---------- ---------- ------------------ ---------- -
a 5 AAACIDAAFAAAAD4AAA 70019 I
a 5 AAACIDAAFAAAAD4AAA 70020 U
c 5 AAACIDAAFAAAAD4AAA 70021 U
c 5 AAACIDAAFAAAAD4AAA 70022 D

SQL> insert into t_pk values (1, 'a', 5);

已创建 1 行。

SQL> update t_pk set name = 'c' where id = 1;

已更新 1 行。

SQL> delete t_pk;

已删除 1 行。

SQL> select id, dmltype$$ from mlog$_t_pk;

ID D
---------- -
1 I
1 U
1 D

SQL> insert into t_oid values (1, 'a', 5);

已创建 1 行。

SQL> update t_oid set name = 'c' where id = 1;

已更新 1 行。

SQL> delete t_oid;

已删除 1 行。

SQL> select sys_nc_oid$, dmltype$$ from mlog$_t_oid;

SYS_NC_OID$ D
-------------------------------- -
9F6DA94248EE40D5AB1E50700F9566EA I
9F6DA94248EE40D5AB1E50700F9566EA U
9F6DA94248EE40D5AB1E50700F9566EA

D

SQL> rollback;

回退已完成。

二、时间列

当基本发生DML操作时,会记录到物化视图日志中,这时指定的时间4000年1月1日0时0分0秒。如果物化视图日志供多个物化视图使用,则一个物化视图刷新后会将它刷新的记录的时间更新为它刷新的时间。

下面建立快速刷新的两个物化视图来演示时间列的变化。(只有建立快速刷新的物化视图才能使用物化视图日志,如果只建立一个物化视图,则物化视图刷新完会将物化视图日志清除掉。

SQL> create materialized view mv_t_rowid refresh fast on commit as
2 select name, count(*) from t_rowid group by name;

实体化视图已创建。

SQL> create materialized view mv_t_rowid1 refresh fast as
2 select name, count(*) from t_rowid group by name;

实体化视图已创建。

SQL> insert into t_rowid values (1, 'a', 5);

已创建 1 行。

SQL> update t_rowid set name = 'c' where id = 1;

已更新 1 行。

SQL> delete t_rowid;

已删除 1 行。

SQL> select snaptime$$ from mlog$_t_rowid;

SNAPTIME$$
-------------------
4000-01-01 00:00:00
4000-01-01 00:00:00
4000-01-01 00:00:00
4000-01-01 00:00:00

SQL> commit;

提交完成。

SQL> select snaptime$$ from mlog$_t_rowid;

SNAPTIME$$
-------------------
2005-03-05 00:40:32
2005-03-05 00:40:32
2005-03-05 00:40:32
2005-03-05 00:40:32

COMMIT后,物化视图mv_t_rowid刷新,将SNAPTIME$$列更新成自己的刷新时间。



三、操作类型和新旧值

操作类型比较简单:只包括I(INSERT)、D(DELETE)和U(UPDATE)三种。

新旧值也包括三种:O表示旧值(一般对应的操作时DELETE)、N表示新值(一般对应的操作是INSERT),还有一种U(对应UPDATE操作)。

SQL> insert into t_pk values (1, 'a', 5);

已创建 1 行。

SQL> insert into t_pk values (2, 'b', 7);

已创建 1 行。

SQL> insert into t_pk values (3, 'c', 9);

已创建 1 行。

SQL> update t_pk set name = 'c' where id = 1;

已更新 1 行。

SQL> update t_pk set id = 4 where id = 2;

已更新 1 行。

SQL> delete t_pk where id = 3;

已删除 1 行。

SQL> select id, dmltype$$, old_new$$ from mlog$_t_pk;

ID D O
---------- - -
1 I N
2 I N
3 I N
1 U U
2 D O
4 I N
3 D O

已选择7行。

开始是插入三条记录,接着是UPDATE操作。需要注意,对于基于主键的物化视图日志,如果更新了主键,则UPDATE操作转化为一条DELETE操作,一条INSERT操作。最后是DELETE操作。

SQL> drop materialized view log on t_rowid;

实体化视图日志已删除。

SQL> create materialized view log on t_rowid with rowid, sequence (name, num) including new values;

实体化视图日志已创建。

SQL> insert into t_rowid values (1, 'a', 5);

已创建 1 行。

SQL> insert into t_rowid

values (2, 'b', 7);

已创建 1 行。

SQL> insert into t_rowid values (3, 'c', 9);

已创建 1 行。

SQL> update t_rowid set name = 'c' where id = 1;

已更新 1 行。

SQL> update t_rowid set id = 4 where id = 2;

已更新 1 行。

SQL> delete t_rowid where id = 3;

已删除 1 行。

SQL> select name, num, m_row$$, dmltype$$, old_new$$ from mlog$_t_rowid;

NAME NUM M_ROW$$ D O
---------- ---------- ------------------ - -
a 5 AAACIDAAFAAAAD4AAC I N
b 7 AAACIDAAFAAAAD4AAA I N
c 9 AAACIDAAFAAAAD4AAB I N
a 5 AAACIDAAFAAAAD4AAC U U
c 5 AAACIDAAFAAAAD4AAC U N
b 7 AAACIDAAFAAAAD4AAA U U
b 7 AAACIDAAFAAAAD4AAA U N
c 9 AAACIDAAFAAAAD4AAB D O

已选择8行。

查询结果和上面类似,唯一的区别是每条UPDATE操作都对应物化视图日志中的两条记录。一条对应UPDATE操作的原记录DMLTYPE$$和OLD_NEW$$都为U,一条对应UPDATE操作后的新记录,DMLTYPE$$为U,OLD_NEW$$为N。当建立物化视图日志时指出了INCLUDING NEW VALUES语句时,就会出现这种情况。



四、修改矢量

最后简单讨论一下CHANGE_VECTOR$$列。

INSERT和DELETE操作都是记录集的,即INSERT和DELETE会影响整条记录。而UPDATE操作是字段集的,UPDATE操作可能会更新整条记录的所有字段,也可能只更新个别字段。

无论从性能上考虑还是从数据的一致性上考虑,物化视图刷新时都应该是基于字段集。Oracle就是通过CHANGE_VECTOR$$列来记录每条记录发生变化的字段包括哪些。

基于主键、ROWID和OBJECT ID的物化视图日志在CHANGE_VECTOR$$上略有不同,但是总体设计的思路是一致的。

CHANGE_VECTOR$$列是RAW类型,其实Oracle采用的方式就是用每个BIT位去映射一个列。

比如:第一列被更新设置为02,即00000010。第二列设置为04,即00000100,第三列设置为08,即00001000。当第一列和第二列同时被更新,则设置为06,00000110。如果三列都被更新,设置为0E,00001110。

依此类推,第4列被更新时为10,第5列20,第6列40,第7列80,第8列0001。当第1000列被更新时,CHANGE_VECTOR$$的长度为1000/4+2为252。

除了可以表示UPDATE的字段,还可以表示INSERT和DELETE。DELETE操作CHANGE_VECTOR$$列为全0,具体个数由基表的列数决定。INSERT操作的最低位为FE如果基表列数较多,而存在高位的话,所有的高位都为FF。如果INSERT操作是前面讨论过的由UPDATE操作更新了主键造成的,则这个INSERT操作对应的CHANGE_VECTOR$$列为全FF。

SQL> insert into t_rowid values (1, 'a', 5);

已创建 1 行。

SQL> insert into t_rowid values (2, 'b', 7);

已创建 1 行。

SQL> insert into t_rowid values (3, 'c', 9);

已创建 1 行。



SQL> update t_rowid set name = 'c' where id = 1;

已更新 1 行。

SQL> update t_rowid set id = 4 where id = 2;

已更新 1 行。

SQL> update t_rowid set name = 'd', num = 11 where id = 3;

已更新 1 行。

SQL> delete t_rowid where id = 3;

已删除 1 行。

SQL> select name, num, m_row$$, dmltype$$, old_new$$, change_vector$$ from mlog$_t_rowid;

NAME NUM M_ROW$$ D O CHANGE_VEC
-------------------- ---------- ------------------ - - ----------
a 5 AAACIgAAFAAAAD4AAA I N FE
b 7 AAACIgAAFAAAAD4AAB I N FE
c 9 AAACIgAAFAAAAD4AAC I N FE
a 5 AAACIgAAFAAAAD4AAA U U 04
c 5 AAACIgAAFAAAAD4AAA U N 04
b 7 AAACIgAAFAAAAD4AAB U U 02
b 7 AAACIgAAFAAAAD4AAB U N 02
c 9 AAACIgAAFAAAAD4AAC U U 0C
d 11 AAACIgAAFAAAAD4AAC U N 0C
d 11 AAACIgAAFAAAAD4AAC D O 00

已选择10行。

可以看到,正如上面分析的,INSERT为FE,DELETE为00,对第一列的更新为02,第二列为04,第二列和第三列都更新为0C。需要注意,正常情况下,第一列会从02开始,但是如果对MLOG$表执行了TRUNCATE操作,或者重建了物化视图日志,则可能造成第一列开始位置发生偏移。

SQL> insert into t_pk values (1, 'a', 5);

已创建 1 行。

SQL> insert into t_pk values (2, 'b', 7);

已创建 1 行。

SQL> insert into t_pk values (3, 'c', 9);

已创建 1 行。

SQL> update t_pk set name = 'c' where id = 1;

已更新 1 行。

SQL> update t_pk set id = 4 where id = 2;

已更新 1 行。

SQL> delete t_pk where id = 1;

已删除 1 行。

SQL> select * from mlog$_t_pk;

ID SNAPTIME$$ D O CHANGE_VEC
---------- ------------------- - - ----------
1 4000-01-01 00:00:00 I N FE
2 4000-01-01 00:00:00 I N FE
3 4000-01-01 00:00:00 I N FE
1 4000-01-01 00:00:00 U U 04
2 4000-01-01 00:00:00 D O 00
4 4000-01-01 00:00:00 I N FF
1 4000-01-01 00:00:00 D O 00

已选择7行。

这个结果和ROWID类型基本一致,不同的是,如果更新了主键,会将UPDATE操作在物化视图日志中记录为一条DELETE和一条INSERT,不过这时INSERT对应的CHANGE_VECTOR$$的值是FF。

SQL> insert into t_oid values (1, 'a', 5);

已创建 1 行。

SQL> update t_oid set name = 'c' where id = 1;

已更新 1 行。

SQL> update t_oid set id = 5 where id = 1;

已更新 1 行。

SQL> delete t_oid;

已删除 1 行。

SQL> select * from mlog$_t_oid;

SYS_NC_OID$ SNAPTIME$$ D O CHANGE_VEC
-------------------------------- ------------------- - - ----------
94216425582C4395A987AFE6303A5CBF 4000-01-01 00:00:00 I

N FE
94216425582C4395A987AFE6303A5CBF 4000-01-01 00:00:00 U U 10
94216425582C4395A987AFE6303A5CBF 4000-01-01 00:00:00 U U 08
94216425582C4395A987AFE6303A5CBF 4000-01-01 00:00:00 D O 00

SQL> select name, segcollength from sys.col$ where obj# =
2 (select object_id from user_objects where object_name = 'T_OID');

NAME SEGCOLLENGTH
-------------------- ------------
SYS_NC_OID$ 16
SYS_NC_ROWINFO$ 1
ID 22
NAME 30
NUM 22

这个结果也和ROWID类型基本一致,需要注意的是,由于对象表包含两个隐含列,因此ID不再是第一个字段,而是第三个,因此对应的值是08。

SQL> create table t (
2 col1 number,
3 col2 number,
4 col3 number,
5 col4 number,
6 col5 number,
7 col6 number,
8 col7 number,
9 col8 number,
10 col9 number,
11 col10 number,
12 col11 number,
13 col12 number
14 );

表已创建。

SQL> create materialized view log on t with rowid;

实体化视图日志已创建。

SQL> insert into t values (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12);

已创建 1 行。

SQL> update t set col1 = 10;

已更新 1 行。

SQL> update t set col11 = 110;

已更新 1 行。

SQL> update t set col5 = 50, col12 = 120;

已更新 1 行。

SQL> delete t;

已删除 1 行。

SQL> select * from mlog$_t;

M_ROW$$ SNAPTIME$$ D O CHANGE_VEC
------------------ ------------------- - - ----------
AAACIyAAFAAAAFgAAA 4000-01-01 00:00:00 I N FEFF
AAACIyAAFAAAAFgAAA 4000-01-01 00:00:00 U U 0200
AAACIyAAFAAAAFgAAA 4000-01-01 00:00:00 U U 0008
AAACIyAAFAAAAFgAAA 4000-01-01 00:00:00 U U 2010
AAACIyAAFAAAAFgAAA 4000-01-01 00:00:00 D O 0000

最后看一个包含列数较多的例子,唯一需要注意的是,低位在左,高位在右。


yangtingkun 发表于:2005.03.04 23:40 ::分类: ( ORACLE ) ::阅读:(10673次) :: 评论 (10) two questions [回复]
hi
请问下面这句怎么理解
“当第1000列被更新时,CHANGE_VECTOR$$的长度为1000/4+2为252,这也是为什么CHANGE_VECTOR$$列的长度要定义为255的原因”
第1000列更新时,10进制值为2的1000次方,即 16的250次方,换算成16进制,即1000...(250个0),那只有250+1=251位. 怎么得出有252位的?
另外,研究过在哪种情况下,用哪种方式创建mlog更有效没有?
tengrid 评论于: 2005.03.22 14:19 [回复]
我这里说法确实有些问题。
当更新1000列时,长度确实是252,但是RAW(1)的最大值就是'FF',因此RAW(1)的长度就是2,这也是为什么1000/4后要加2的原因。
不过CHANGE_VECTOR$$的大小不是刚刚好,而是富裕出一倍,其实只需要RAW(126)就够了。
RAW(255)应该是RAW类型可以存储的最大范围了。
yangtingkun 评论于: 2005.03.22 16:58 re: 心中的疑问 [回复]
我问个

没水平的问题,实体化视图日志中又没有记录主表某个字段更改前的值和更改后的值,Oracle是如何正确的刷新呢?
空虚的猫 评论于: 2007.09.19 10:38 re: 物化视图日志结构 [回复]
Oracle要读基表的
yangtingkun 评论于: 2007.09.19 14:27 re: 物化视图日志结构 [回复]
就是说刷新的时候,oracle通过实体化视图日志的rowid或者其他信息定位到具体哪条记录发生改变,然后用基表这条记录的值来更新其对应的实体化视图的值?如果是这样的话,假如基表的一条记录被update多次后,开始刷新,那么刷新的时候,其实只要有一条update执行,就已经同步了,其余update其实没用了?
小弟接触Oracle不长,这个问题一直想不明白,也没有参考读物,请yangtingkun大侠多多指点啊!
空虚的猫 评论于: 2007.09.21 13:08 re: 物化视图日志结构 [回复]
对于复制用途的物化视图是这样的。
对于包含聚集的物化视图,则有一些区别。
yangtingkun 评论于: 2007.09.23 22:15 re: 物化视图日志结构 [回复]
好文章,谢谢
老血 评论于: 2008.01.25 19:55 re: 物化视图日志结构 [回复]
物化视图刷新如果不需要根据顺序进行刷新,那么就会按照DELETE、INSERT和UPDATE的顺序执行3次操作
yangtingkun 评论于: 2009.05.31 23:26 re: 物化视图日志结构 [回复]
斑竹,
在建MATERIALIZED VIEW LOG没有用sequence()
创建包含有聚集的物化视图时报错,还是不太明白sequence()怎样用?
SQL> desc lgx;
Name Type Nullable Default Comments
---- ------------ -------- ------- --------
A INTEGER Y
B VARCHAR2(10) Y
CREATE MATERIALIZED VIEW mv_lgx
REFRESH FAST ON DEMAND
WITH ROWID
START WITH TO_DATE('17-08-2009 17:09:16', 'DD-MM-YYYY HH24:MI:SS') NEXT /*1:HRS*/ SYSDATE + 1/(24*60)
AS
SELECT a,count(*) FROM lgx group by a
ORA-12033: cannot use filter columns from materialized view log on "LGX_TEST"."LGX"
lgxswfc 评论于: 2009.08.18 12:30 re: 物化视图日志结构 [回复]
你这种情况可以不要SEQUENCE,但是必须包含A列。
具体的描述还是去看Oracle的文档吧。










Oracle物化视图的快速刷新机制是通过物化视图日志完成的。Oracle如何通过一个物化视图日志就可以支持多个物化视图的快速刷新呢,本文简单的描述一下刷新的原理。





首先,看一下物化视图的结构:

SQL> create table t (id number, name varchar2(30), num number);

表已创建。

SQL> create materialized view log on t with rowid, sequence (id, name) including new values ;

实体化视图日志已创建。

SQL> desc mlog$_t
名称 是否为空? 类型
---------------------------------------- -------- ------------
ID NUMBER
NAME VARCHAR2(3

0)
M_ROW$$ VARCHAR2(255)
SEQUENCE$$ NUMBER
SNAPTIME$$ DATE
DMLTYPE$$ VARCHAR2(1)
OLD_NEW$$ VARCHAR2(1)
CHANGE_VECTOR$$ RAW(255)

ID和NAME是建立物化视图日志时指定的基表中的列,它们记录每次DML操作对应的ID和NAME的值。

M_ROW$$保存基表的ROWID信息,根据M_ROW$$中的信息可以定位到发生DML操作的记录。

SEQUENCE$$根据DML操作发生的顺序记录序列的编号,当刷新时,根据SEQUENCE$$中的顺序就可以和基表中的执行顺序保持一致。

SNAPTIME$$列记录了刷新操作的时间。

DMLTYPE$$的记录值I、U和D,表示操作是INSERT、UPDATE还是DELETE。

OLD_NEW$$表示物化视图日志中保存的信息是DML操作之前的值(旧值)还是DML操作之后的值(新值)。除了O和N这两种类型外,对于UPDATE操作,还可能表示为U。

CHANGE_VECTOR$$记录DML操作发生在那个或那几个字段上。

有关物化视图日志结构的详细描述,可以参考文档:

物化视图日志结构:https://www.wendangku.net/doc/bc15833688.html,/post/468/20498

根据上面的描述,可以发现,当刷新物化视图时,只需要根据SEQUENCE$$列给出的顺序,通过M_ROW$$定位到基表的记录,如果是UPDATE操作,通过CHANGE_VECTOR$$定位到字段,然后根据基表中的数据重复执行DML操作。

如果物化视图日志只针对一个物化视图,那么刷新过程就是这么简单,还需要做的不过是在刷新之后将物化视图日志清除掉。

但是,Oracle的物化视图日志是可以同时支持多个物化视图的快速刷新的,也就是说,物化视图在刷新时还必须判断哪些物化视图日志记录是当前物化视图刷新需要的,哪些是不需要的。而且,物化视图还必须确定,在刷新物化视图后,物化视图日志中哪些记录是需要清除的,哪些是不需要清除的。

回顾一下物化视图日志的结构,发现只剩下一个SHAPTIME$$列,那么Oracle如何仅通过这一列就完成了对多个物化视图的支持呢?下面建立一个小例子,通过例子来进行说明。

使用上文中建立的表和物化视图日志,下面对这个表建立三个快速刷新的物化视图。

SQL> create materialized view mv_t_id refresh fast as
2 select id, count(*) from t group by id;

实体化视图已创建。

SQL> create materialized view mv_t_name refresh fast as
2 select name, count(*) from t group by name;

实体化视图已创建。

SQL> create materialized view mv_t_id_name refresh fast as
2 select id, name, count(*) from t group by id, name;

实体化视图已创建。

SQL> insert into t values (1, 'a', 2);

已创建 1 行。

SQL> in

sert into t values (1, 'b', 3);

已创建 1 行。

SQL> insert into t values (2, 'a', 5);

已创建 1 行。

SQL> insert into t values (3, 'b', 7);

已创建 1 行。

SQL> update t set name = 'c' where id = 3;

已更新 1 行。

SQL> delete t where id = 2;

已删除 1 行。

SQL> select id, name, m_row$$, snaptime$$, dmltype$$ from mlog$_t;

ID NAME M_ROW$$ SNAPTIME$$ D
---------- ---------- ------------------ ------------------- -
1 a AAACJEAAFAAAAD4AAA 4000-01-01 00:00:00 I
1 b AAACJEAAFAAAAD4AAB 4000-01-01 00:00:00 I
2 a AAACJEAAFAAAAD4AAC 4000-01-01 00:00:00 I
3 b AAACJEAAFAAAAD4AAD 4000-01-01 00:00:00 I
3 b AAACJEAAFAAAAD4AAD 4000-01-01 00:00:00 U
3 c AAACJEAAFAAAAD4AAD 4000-01-01 00:00:00 U
2 a AAACJEAAFAAAAD4AAC 4000-01-01 00:00:00 D

已选择7行。

当发生了DML操作后,物化视图日志中的SNAPTIME$$列保持的值是4000-01-01 00:00:00。这个值表示这条记录还没有被任何物化视图刷新过。第一个刷新这些记录的物化视图会将SNAPTIME$$的值更新为物化视图当前的刷新时间。
SQL> exec dbms_mview.refresh('MV_T_ID')

PL/SQL 过程已成功完成。

SQL> select id, name, m_row$$, snaptime$$, dmltype$$ from mlog$_t;

ID NAME M_ROW$$ SNAPTIME$$ D
---------- ---------- ------------------ ------------------- -
1 a AAACJEAAFAAAAD4AAA 2005-03-06 00:56:59 I
1 b AAACJEAAFAAAAD4AAB 2005-03-06 00:56:59 I
2 a AAACJEAAFAAAAD4AAC 2005-03-06 00:56:59 I
3 b AAACJEAAFAAAAD4AAD 2005-03-06 00:56:59 I
3 b AAACJEAAFAAAAD4AAD 2005-03-06 00:56:59 U
3 c AAACJEAAFAAAAD4AAD 2005-03-06 00:56:59 U
2 a AAACJEAAFAAAAD4AAC 2005-03-06 00:56:59 D

已选择7行。

Oracle根据数据字典中的信息可以知道表T上建立了三个物化视图,因此,MV_T_ID刷新完之后,不会删除物化视图记录。
Oracle的数据字典中还保存着每个物化视图上次刷新的时间和当前的刷新状态。
SQL> select name, last_refresh from user_mview_refresh_times;

NAME LAST_REFRESH
------------------------------ -------------------
MV_T_ID 2005-03-06 00:56:59
MV_T_ID_NAME 2005-03-06 00:46:09
MV_T_NAME 2005-03-06 00:46:04

SQL> select mview_name, last_refresh_date, staleness from user_mviews;

MVIEW_NAME LAST_REFRESH_DATE STALENESS
------------------------------ ------------------- -------------------
MV_T_ID 2005-03-06 00:56:59 FRESH
MV_T_ID_NAME 2005-03-06 00:46:09 NEEDS_COMPILE
MV_T_NAME 2005-03-06 00:46:04 NEEDS_COMPILE

这些视图中记录

了每个物化视图上次执行刷新操作的时间,并且给出每个物化视图中的数据是否是和基表同步的。由于MV_T_ID刚刚进行了刷新,因此状态是FRESH,而另外两个由于在刷新(建立)之后,基表又进行了DML操作,因此状态为NEEDS_COMPILE。如果这时对基表进行DML操作,则MV_T_ID的状态也会变为NEEDS_COMPILE。

SQL> insert into t values (4, 'd', 10);

已创建 1 行。

SQL> commit;

提交完成。

SQL> select id, name, m_row$$, snaptime$$, dmltype$$ from mlog$_t;

ID NAME M_ROW$$ SNAPTIME$$ D
---------- ---------- ------------------ ------------------- -
1 a AAACJEAAFAAAAD4AAA 2005-03-06 00:56:59 I
1 b AAACJEAAFAAAAD4AAB 2005-03-06 00:56:59 I
2 a AAACJEAAFAAAAD4AAC 2005-03-06 00:56:59 I
3 b AAACJEAAFAAAAD4AAD 2005-03-06 00:56:59 I
3 b AAACJEAAFAAAAD4AAD 2005-03-06 00:56:59 U
3 c AAACJEAAFAAAAD4AAD 2005-03-06 00:56:59 U
2 a AAACJEAAFAAAAD4AAC 2005-03-06 00:56:59 D
4 d AAACJEAAFAAAAD4AAE 4000-01-01 00:00:00 I

已选择8行。

SQL> select mview_name, last_refresh_date, staleness from user_mviews;

MVIEW_NAME LAST_REFRESH_DATE STALENESS
------------------------------ ------------------- -------------------
MV_T_ID 2005-03-06 00:56:59 NEEDS_COMPILE
MV_T_ID_NAME 2005-03-06 00:46:09 NEEDS_COMPILE
MV_T_NAME 2005-03-06 00:46:04 NEEDS_COMPILE

下面刷新物化视图MV_T_ID_NAME,刷新操作的判断依据是,只刷新SNAPTIME$$列大于当前物化视图的LAST_REFRESH_DATE的记录,由于物化视图日志中所有记录的SNAPTIME$$的值都比物化视图MV_T_ID_NAME上次刷新的时间点大,因此会刷新所有记录。对于SNAPTIME$$列的值是4000-01-01 00:00:00的记录,物化视图会把SNAPTIME$$列的值更新为当前刷新时间,对于那些已经被更新过的SNAPTIME$$列,则保持原值。

SQL> exec dbms_mview.refresh('MV_T_ID_NAME')

PL/SQL 过程已成功完成。

SQL> select id, name, m_row$$, snaptime$$, dmltype$$ from mlog$_t;

ID NAME M_ROW$$ SNAPTIME$$ D
---------- ---------- ------------------ ------------------- -
1 a AAACJEAAFAAAAD4AAA 2005-03-06 00:56:59 I
1 b AAACJEAAFAAAAD4AAB 2005-03-06 00:56:59 I
2 a AAACJEAAFAAAAD4AAC 2005-03-06 00:56:59 I
3 b AAACJEAAFAAAAD4AAD 2005-03-06 00:56:59 I
3 b AAACJEAAFAAAAD4AAD 2005-03-06 00:56:59 U
3 c AAACJEAAFAAAAD4AAD 2005-03-06 00:56:59 U
2 a AAACJEAAFAAAAD4AAC 2005-03-06 00:56:59 D
4 d AAACJEAAFAAAAD4AAE 2005-03-06 01:18:22 I

已选择8行。

SQL> select mview_name, last_refresh_date, staleness from u

ser_mviews;

MVIEW_NAME LAST_REFRESH_DATE STALENESS
------------------------------ ------------------- -------------------
MV_T_ID 2005-03-06 00:56:59 NEEDS_COMPILE
MV_T_ID_NAME 2005-03-06 01:18:22 FRESH
MV_T_NAME 2005-03-06 00:46:04 NEEDS_COMPILE

如果这时再次刷新物化视图MV_T_ID,则只有ID=4的这条记录的SNAPTIME$$的时间点大于MV_T_ID上次刷新的时间点,因此,只刷新这一条记录,且不会改变SNAPTIME$$的值。
SQL> exec dbms_mview.refresh('MV_T_ID')

PL/SQL 过程已成功完成。

SQL> select id, name, m_row$$, snaptime$$, dmltype$$ from mlog$_t;

ID NAME M_ROW$$ SNAPTIME$$ D
---------- ---------- ------------------ ------------------- -
1 a AAACJEAAFAAAAD4AAA 2005-03-06 00:56:59 I
1 b AAACJEAAFAAAAD4AAB 2005-03-06 00:56:59 I
2 a AAACJEAAFAAAAD4AAC 2005-03-06 00:56:59 I
3 b AAACJEAAFAAAAD4AAD 2005-03-06 00:56:59 I
3 b AAACJEAAFAAAAD4AAD 2005-03-06 00:56:59 U
3 c AAACJEAAFAAAAD4AAD 2005-03-06 00:56:59 U
2 a AAACJEAAFAAAAD4AAC 2005-03-06 00:56:59 D
4 d AAACJEAAFAAAAD4AAE 2005-03-06 01:18:22 I

已选择8行。

SQL> select mview_name, last_refresh_date, staleness from user_mviews;

MVIEW_NAME LAST_REFRESH_DATE STALENESS
------------------------------ ------------------- -------------------
MV_T_ID 2005-03-06 01:25:30 FRESH
MV_T_ID_NAME 2005-03-06 01:18:22 FRESH
MV_T_NAME 2005-03-06 00:46:04 NEEDS_COMPILE

到目前为止,还没有看到过物化视图日志的清除,其实每次进行完刷新,物化视图日志都会试图删除没有用的物化视图日志记录。物化视图日志记录的删除条件是删除那些SNAPTIME$$列小于等于基表所有物化视图的上次刷新时间。在上面的例子中,由于MV_T_NAME一直没有刷新,因此它的LAST_REFRESH_DATE比物化视图日志中所有记录的值都小,因此,一直没有发生物化视图日志记录清除的现象。
SQL> insert into t values (5, 'e', 2);

已创建 1 行。

SQL> commit;

提交完成。

SQL> exec dbms_mview.refresh('MV_T_NAME')

PL/SQL 过程已成功完成。

SQL> select id, name, m_row$$, snaptime$$, dmltype$$ from mlog$_t;

ID NAME M_ROW$$ SNAPTIME$$ D
---------- ---------- ------------------ ------------------- -
5 e AAACJEAAFAAAAD4AAF 2005-03-06 01:31:33 I

SQL> select mview_name, last_refresh_date, staleness from user_mviews;

MVIEW_NAME LAST_REFRESH_DATE STALENESS
------------------------------ ------------------- -------------------
MV_T_ID 2005-03-06 01:25:30 NEEDS_COMPILE
MV_T_ID_NAME

2005-03-06 01:18:22 NEEDS_COMPILE
MV_T_NAME 2005-03-06 01:31:33 FRESH

物化视图MV_T_NAME刷新了物化视图中的每条记录,更新了ID=5的记录的SNAPTIME$$时间,并清除了其它所有物化视图日志记录。
最后,简单总结一下:
物化视图在刷新时,会刷新所有SNAPTIME$$大于本物化视图上次刷新时间的记录,并将所有是4000-01-01 00:00:00的记录更新为当前刷新时间。对于其他大于上次刷新时间的记录,只刷新不更改。这样,当刷新执行完以后,数据字典中记录当前物化视图的上次刷新时间为当前时刻,这保证了物化视图日志中目前所有的记录都小于或等于刷新时间。因此,每个物化视图只要刷新大于上次刷新时间的记录,且保证每次刷新后,所有记录的时间都小于等于上次刷新时间,那么无论有多少个物化视图,就可以互不影响的使用同一个物化视图日志进行快速刷新了。当物化视图刷新完之后,会清除那些SNAPTIME$$列小于所有物化视图的上次刷新时间的记录,而这些记录已经被所有的物化视图都刷新过了,保存在物化视图日志中已经没有意义了。



yangtingkun 发表于:2005.03.05 23:49 ::分类: ( ORACLE ) ::阅读:(19342次) :: 评论 (18) [回复]
很好的关于mv的文章,收藏.
tengrid 评论于: 2005.03.22 14:34 re: Oracle如何根据物化视图日志快速刷新物化视图 [回复]
若更改了系统时间,会不会造成日志里未刷新到物化视图的
数据,提前被删除?
ZALBB 评论于: 2006.08.14 19:06 re: Oracle如何根据物化视图日志快速刷新物化视图 [回复]
不会,只有物化视图的刷新时刻才会去清除物化视图日志信息
yangtingkun 评论于: 2006.08.14 20:36 re: Oracle如何根据物化视图日志快速刷新物化视图 [回复]
假设A为日志表,B、C为物化视图。
刷新前,系统时间修改了,比C的上次刷新时间还小,
这样,B刷新时,A里的记录的SNAPTIME$$被改为比
C的last_refresh_time小,那系统会不会删除
A的记录?
ZALBB 评论于: 2006.08.16 16:04 re: Oracle如何根据物化视图日志快速刷新物化视图 [回复]
我是说,人为地去修改服务器的时间,ORACLE不也用的是
服务器的时间吗?
ZALBB 评论于: 2006.08.17 14:05 re: Oracle如何根据物化视图日志快速刷新物化视图 [回复]
估计你没有仔细看我给你的链接
那篇文章讨论的就是人为或其他因素导致操作系统时间发生变化后,Oracle物化视图的时间戳机制
简单的话,如果操作系统时间比Oracle存储的时间大,则使用系统时间,否则在上次刷新时间的基础上增加1秒作为新的时间
yangtingkun 评论于: 2006.08.17 16:26 re: Oracle如何根据物化视图日志快速刷新物化视图 [回复]
不知道什么原因我的结果总


SQL> select mview_name, last_refresh_date, staleness from user_mviews;
MVIEW_NAME LAST_REFRE STALENESS
------------------------------ ---------- ---------
MV_T_ID 11-6月 -07 FRESH
MV_T_ID_NAME 11-6月 -07 FRESH
MV_T_NAME 11-6月 -07 FRESH
没有出现过NEEDS_COMPILE
howard_zhang 评论于: 2007.06.11 12:01 re: Oracle如何根据物化视图日志快速刷新物化视图 [回复]
根据我上面的例子,把所有的步骤和结果都贴出来
yangtingkun 评论于: 2007.06.12 11:14 re: Oracle如何根据物化视图日志快速刷新物化视图 [回复]
杨版主,在建物化视图的时候没有指定用物化视图日志,oracle如何知道要使用哪个日志呢?
Eason.Cai 评论于: 2007.10.25 19:56 re: Oracle如何根据物化视图日志快速刷新物化视图 [回复]
数据字典中记录会记录这个信息的
yangtingkun 评论于: 2007.10.26 12:40 re: Oracle如何根据物化视图日志快速刷新物化视图 [回复]
当物化视图刷新完之后,会清除那些SNAPTIME$$列小于所有物化视图的上次刷新时间的记录,而这些记录已经被所有的物化视图都刷新过了,保存在物化视图日志中已经没有意义了。
MLOG怎么知道是“所有”都已经刷新了呢?在哪个数据字典上查呢?他是根据什么判断已经所有在这表上建了物化视图的都已经刷新呢?
ongtin 评论于: 2008.08.11 17:10 re: Oracle如何根据物化视图日志快速刷新物化视图 [回复]
通过查询数据字典可以获取这个信息。
上面的例子中就有体现,你再仔细看看
yangtingkun 评论于: 2008.08.15 15:28 re: Oracle如何根据物化视图日志快速刷新物化视图 [回复]
.请教版主。物化视图的被库重启之后不自动刷新了,请问这个如何才能继续刷新?
replicate 评论于: 2009.02.17 00:14 re: Oracle如何根据物化视图日志快速刷新物化视图 [回复]
和数据库是否重启没有关系,看看JOB是否自动运行的原因吧
yangtingkun 评论于: 2009.02.18 15:36 re: Oracle如何根据物化视图日志快速刷新物化视图 [回复]
创建物化视图的时候
查询里面有关键字 rownum 是不是不能使用 on commit
ji 评论于: 2009.12.23 15:37 re: Oracle如何根据物化视图日志快速刷新物化视图 [回复]
有rownum是无法快速刷新的,至于能不能ON COMMIT就不清除了,不过一般来说无法快速刷新,就是能ON COMMIT也没有任何的意义。
yangtingkun 评论于: 2009.12.27 15:16 re: Oracle如何根据物化视图日志快速刷新物化视图 [回复]
"对于其他大于上次刷新时间的记录,只刷新不更改。"这个指的是什么呢?
wangliang 评论于: 2010.06.23 17:44 re: Oracle如何根据物化视图日志快速刷新物化视图 [回复]
比如物化视图刷新的时候发现上次刷新时间是今天的1点,这时发现一条时间戳为4000-1-1的记录和一条时间戳为

今天3点的记录,对于4000-1-1的记录,时间戳被改写为当前时间,而对于今天3点的记录,时间戳不改变


相关文档