深入理解:
物化视图日志是用来记录基表更细操作的一种特殊日志表,物化视图的快速刷新要求基本必须建立物化视图日志。物化视图日志的名称为MLOG$_后面跟基表的名称,如果表名的长度超过20位,则只取前20位,当截短后出现名称重复时,Oracle会自动在物化视图日志名称后面加上数字作为序号。
任何物化视图都会包括的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名称,则物化视图日志中会包含这些列。
1,故障模拟
createtable t_info_a(idnumber(10),namevarchar2(30));
altertable t_info_a addconstraint pk_id01 primarykey(id);
insertinto t_info_a
select111,'kkk'from dual;
SELECT*FROM t_info_a;
CREATEMATERIALIZEDVIEWLOGON t_info_a
WITHPRIMARYKEY
INCLUDINGNEWVALUES;
select*from all_mview_logs;
CREATEMATERIALIZEDVIEW MV_t_info_a --创建物化视图
BUILDIMMEDIATE --在视图编写好后创建
REFRESHFASTWITHPRIMARYKEY --根据主表主键增量刷新(FAST,增量)
ONDEMAND -- 在用户需要时,由用户刷新
ENABLEQUERYREWRITE --可读写
AS
SELECT*FROM t_info_a;--查询语句
drop table MLOG$_T_INFO_A;
SELECT*FROM T_INFO_A;
update T_INFO_A a set a.name ='rrrr'whereid=111;
相应的
insert into T_INFO_A
select 222,'tttt' from dual;
delete from T_INFO_A where id = 111;
都会报同样的错误;
(如果在生产中基表是核心信息表,那么造成的灾难不可预估.)
2,解决办法
只需要如下一条命令即可:
drop materialized view log on T_INFO_A;
--DROP MATERIALIZED VIEW "BTUXX"."MLOG$_T_INFO_A";
验证问题是否已解决:
update T_INFO_A a
set a.name ='rrrr'whereid=111;
insertinto T_INFO_A
select222,'tttt'from dual;
deletefrom T_INFO_A whereid=111;
没有报错,而且相应操作也成功。
3,生产环境中正确操作步骤演练
create table t_info_b(idnumber(10),namevarchar2(30));
insert into t_info_b
select 111,'kkk' from dual;
alter table t_info_b add constraint pk_id02 primary key(id);
SELECT * FROM t_info_b;
先创建物化视图:
CREATE MATERIALIZED VIEW LOGON t_info_b
WITH PRIMARYKEY
INCLUDING NEWVALUES;
--查看物化视图日志信息
select*from all_mview_logs t
where t.MASTER ='T_INFO_B'
--创建物化视图(其实这步可有可无)
CREATE MATERIALIZED VIEW MV_t_info_b --创建物化视图
BUILD IMMEDIATE --在视图编写好后创建
REFRESH FAST WITH PRIMARY KEY --根据主表主键增量刷新(FAST,增量)
ON DEMAND -- 在用户需要时,由用户刷新
ENABLE QUERY REWRITE --可读写
AS
SELECT * FROM t_info_b; --查询语句
现在假设MLOG$_T_INFO_B这个表很大(如:100G),需要删除以释放空间资源。该如何解决呢?
朋友们:看到MLOG$_开头的东西的时候要注意了,千万别跟删普通表一样的删除,千万不要drop table MLOG$_T_INFO_B;这样的命令了。否则灾难就找上门来了。
正确的做法是:理解MLOG$_T_INFO_B这个是表T_INFO_B上的物化视图日志,然后用如下命令删除。
drop materialized view log on "BTUXX"."T_INFO_B";
--完成后我们来看看
SELECT * FROM t_info_b;
insert into t_info_b select 222,'hhhhh' from dual
相应的修改和删除也能成功(你可以试试)
4、ORACLE自动完成物化视图日志的删除
4.1刷新物化视图会清空物化视图日志表
物化视图的日志清除一般是由Oracle自动完成的。Oracle会根据物化视图基表上的注册信息和物化视图的刷新来确定何时删除物化视图日志。
insert into t_info_a select 888,'kkk' from dual;
SELECT * FROM MLOG$_T_INFO_A;
但表结构还在,不过由于数据库链的连接用户是BTUXX拥有对MLOG$_T_INFO_A的删除权限。可以试一下普通用户,只赋给他查询物化视图的权限,也可以自动清除掉。可见物化视图日志的清除完全是Oracle的内容操作,与用户的权限没有关系。
4.2删除物化视图,也可以清空物化视图日志表
SELECT*FROM MLOG$_T_INFO_A; --没有记录
可见,删除物化视图,也可以清除物化视图日志数据。
总结:如果不需要删除物化视图日志表本身,那么基表上的DML操作都会都会往物化视图日志表里面写数据。如果不想要产生日志,减少占用空间资源,还是需要如下命令才行:
drop materialized view log on "T_INFO_B"
总结:
想要删除"MLOG$_T_INFO_B"表,正确的操作是
drop materialized view log on "T_INFO_B";
而不是drop materialized view log on "MLOG$_T_INFO_B";
也不是 drop table "MLOG$_T_INFO_B";
虽然drop table “MLOG$_T_INFO_B";命令能把物化视图日志本身删除,释放空间,但是它并没有解除(基表和日志表之间)依赖关系。没有解除这种关系,对于查询不会报错,但是增、删、改均会报错。
评论
