物化视图日志

分类: PL/SQL编程 |
物化视图日志的作用是什么?为什么要建立物化视图日志?这是我看到这个名词的时候,脑子里第一个想到的问题。经过在网上的一番探索,终于知道物化视图的是干什么的了
物化视图日志--是为物化视图的快速刷新服务的。
物化视图有个刷新方法叫FAST(快速刷新,也就是增量刷新),如果我们想用这种刷新方法,就必须先为基表建立物化视图日志。也就是说,物化视图的快速刷新要求必须建立物化视图日志。
那么,就详细介绍下物化视图日志
1.物化视图日志的名称为MLOG$_后面跟基表的名称,如果表名的长度超过20位,则只取前20位,当截短后出现名称重复时,Oracle会自动在物化视图日志名称后面加上数字作为序号
2.物化视图日志在建立时有多种选项:可以指定为ROWID、PRIMARY KEY和OBJECT ID几种类型,同时还可以指定SEQUENCE或明确指定列名。上面这些情况产生的物化视图日志的结构都不相同
3.任何物化视图日志都会包括的4列:
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名称,则物化视图日志中会包含这些列
4.物化视图日志列的说明
一、主键列、ROWID列、OBJECT
ID列、SEQUENCE列和建立物化视图时指明的列。
主键、ROWID或OBJECT ID用来唯一表示物化视图日志中的记录。
SEQUENCE会根据操作发生的顺序对物化视图日志中的记录编号。
CREATE TABLE T_ROWID (ID NUMBER, NAME VARCHAR2(30), NUM
NUMBER);
CREATE MATERIALIZED VIEW LOG ON T_ROWID WITH ROWID, SEQUENCE(NAME,
NUM) INCLUDING NEW VALUES;
SELECT * FROM MLOG$_T_ROWID;
CREATE TABLE T_PK (ID NUMBER PRIMARY KEY, NAME VARCHAR2(30), NUM
NUMBER);
CREATE MATERIALIZED VIEW LOG ON T_PK WITH PRIMARY KEY;
SELECT * FROM MLOG$_T_PK;
CREATE TYPE T_OBJECT AS OBJECT
(
);
CREATE TABLE T_OID OF T_OBJECT;
CREATE MATERIALIZED VIEW LOG ON T_OID WITH OBJECT ID;
SELECT * FROM MLOG$_T_OID;
INSERT INTO T_PK VALUES (1, 'a', 5);
UPDATE T_PK SET NAME = 'c' WHERE ID = 1;
DELETE T_PK;
SELECT * FROM MLOG$_T_PK;
ID
--- -------------- ------------- --------------
--------------------- ------------
1
1
1
INSERT INTO T_OID VALUES (1, 'a', 5);
UPDATE T_OID SET NAME = 'c' WHERE ID = 1;
DELETE T_OID;
SELECT * FROM MLOG$_T_OID;
SYS_NC_OID$
-------------------------------- ---------- --------- ---------
----------------
22D85F59953E45E081CAA016
4000/1/1
22D85F59953E45E081CAA016
4000/1/1
ROLLBACK;
二、时间列
CREATE MATERIALIZED VIEW MV_T_ROWID
BUILD IMMEDIATE
REFRESH FAST ON COMMIT
AS
SELECT NAME, COUNT(*) FROM T_ROWID GROUP BY NAME;
CREATE MATERIALIZED VIEW MV_T_ROWID1
REFRESH FAST
AS SELECT NAME, COUNT(*) FROM T_ROWID GROUP BY NAME;
INSERT INTO T_ROWID VALUES (1, 'A', 5);
UPDATE T_ROWID SET NAME = 'C' WHERE ID = 1;
DELETE T_ROWID;
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
COMMIT;
SELECT SNAPTIME$$ FROM MLOG$_T_ROWID;
SNAPTIME$$
-------------------
2012/5/23 15:41:41
2012/5/23 15:41:41
2012/5/23 15:41:41
2012/5/23 15:41:41
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;
---------- - -
已选择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
---------- ---------- ------------------ - -
a
b
c
a
c
b
b
c
已选择8行。
查询结果和上面类似,唯一的区别是每条UPDATE操作都对应物化视图日志中的两条记录。一条对应UPDATE操作的原记录DMLTYPE$$和OLD_NEW$$都为U,一条对应UPDATE操作后的新记录,DMLTYPE$$为U,OLD_NEW$$为N。当建立物化视图日志时指出了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> 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;
可以看到,正如上面分析的,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> commit
提交完成。
SQL> select * from mlog$_t_pk;
http://pic002.cnblogs.com/images/2012/270324/2012052316213625.png
这个结果和ROWID类型基本一致,不同的是,如果更新了主键,会将UPDATE操作在物化视图日志中记录为一条DELETE和一条INSERT,不过这时INSERT对应的CHANGE_VECTOR$$的值是FF。
已创建 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> commit;
提交完成。
SQL> select * from mlog$_t_oid;
http://pic002.cnblogs.com/images/2012/270324/2012052316303010.png
SQL> select name, segcollength from sys.col$ where obj# = (select object_id from user_objects where object_name ='T_OID');
NAME
------------------------------ ------------
SYS_NC_OID$
SYS_NC_ROWINFO$
ID
NAME
NUM
这个结果也和ROWID类型基本一致,需要注意的是,由于对象表包含两个隐含列,因此ID不再是第一个字段,而是第三个,因此对应的值是08。
SQL> create table t (
);
表已创建。
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> commit;
提交完成。
SQL> select * from mlog$_t;
http://pic002.cnblogs.com/images/2012/270324/2012052316362156.png
最后看一个包含列数较多的例子,唯一需要注意的是,低位在左,高位在右。