学习ORACLE-物化视图(MATERIALIZED VIEW)总结

数据仓库项目中使用物化视图推送数据,现记录一下相关方面的知识。
物化视图需要有基表,基表可以在本地库,也可以在远程库。可以在本地通过数据库链接访问远程库的基表

基表:hr.departments@orcl
物化视图:scott.departments@orcl1

1.快速刷新的物化视图需要在基表上建立物化视图日志

在orcl库hr用户上的departments上创建物化视图日志

CREATE MATERIALIZED VIEW LOG ON DEPARTMENTS;
SELECT * FROM ALL_MVIEW_LOGS;

查询数据字典发现生成了一个基于主键的物化视图日志MLOG$_DEPARTMENTS,结构如下

NAME TYPE
DEPARTMENT_ID NUMBER(4)
SNAPTIME$$ DATE
DMLTYPE$$ VARCHAR2(1)
OLD_NEW$$ VARCHAR2(1)
CHANGE_VECTOR$$ RAW(255)
XID$$ NUMBER

DEPARTMENT_ID:基表的主键,默认创建的物化视图日志为子句 with primar key,日志表会包含基表的主键列;
SNAPTIME$$:填充刷新时间;
DMLTYPE$$:填充DML操作的类型,I表示插入、D表示删除、U表示更新;
OLD_NEW$$:表示值的新旧,N表示新值,对应插入操作;O表示旧值,对应删除操作;U表示更新值,对应更新操作;
CHANGE_VECTOR$$:表示修改矢量,用来表示被修改的是哪个或哪几个字段 ;
XID$$:基于current scn类型的物化视图日志会用到XID列,该列与current scn 的对应关系存储在视图ALL_SUMMAP中;

创建物化视图日志的标准语句为

create_materialized_vw_log::=
CREATE MATERIALIZED VIEW LOG
  ON [ schema. ] table
  [ physical_attributes_clause
  | TABLESPACE tablespace
  | logging_clause
  | { CACHE | NOCACHE }
    [ physical_attributes_clause
    | TABLESPACE tablespace
    | logging_clause
    | { CACHE | NOCACHE }
    ]...
  ]
  [ parallel_clause ]
  [ table_partitioning_clauses ]
  [ WITH { OBJECT ID
         | PRIMARY KEY
         | ROWID
         | SEQUENCE
         | (column [, column ]...)
         }
           [, { OBJECT ID
              | PRIMARY KEY
              | ROWID
              | SEQUENCE
              | (column [, column ]...)
              }
           ]...
    [ new_values_clause ]
  ] ;
  
  physical_attributes_clause::=
  [ { PCTFREE integer
  | PCTUSED integer
  | INITRANS integer
  | storage_clause
  }
    [ PCTFREE integer
    | PCTUSED integer
    | INITRANS integer
    | storage_clause
    ]...
]

logging_clause::=
{ LOGGING | NOLOGGING }

parallel_clause::=
{ NOPARALLEL | PARALLEL [ integer ] }

new_values_clause::=
{ INCLUDING | EXCLUDING } NEW VALUES

关键字解读
OBJECT ID:则物化视图日志中会包含SYS_NC_OID$,用来记录每个变化行的对象标识符;
PRIMARY KEY:则物化视图日志中会包含主键列;
ROWID:则物化视图日志中会包含M_ROW$$,用来存储发生变化所有行的ROWID;
SEQUENCE:物化视图日志中会包含SEQUENCE$$,用来记录DML操作顺序的编号,保证刷新按顺序刷新,由于无法唯一定位记录,一般不单独使用;
对于关键字INCLUDING NEW VALUES,表示在日志中同时保留新值和旧值,如果此日志的基表的物化视图是单表聚合视图且需要快速刷新,则要指定该关键字;
对于关键字EXCLUDING NEW VALUES,表示禁用在日志中记录新值,以此避免开销;

2.创建快速刷新的物化视图

在orcl1 的scott下创建一个名为departments_1的物化视图,一个名为departments_2的物化视图和一个名为departments_3的物化视图,它们的master table为 orcl库hr用户下的departments

--创建departments_1 
CREATE MATERIALIZED VIEW DEPARTMENTS_1 
AS
SELECT * FROM HR.DEPARTMENTS@HR_ORCL_LOCALHOST;
--创建departments_2
CREATE MATERIALIZED VIEW DEPARTMENTS_2
AS
SELECT * FROM HR.DEPARTMENTS@HR_ORCL_LOCALHOST;
--创建departments_2
CREATE MATERIALIZED VIEW DEPARTMENTS_2
AS
SELECT * FROM HR.DEPARTMENTS@HR_ORCL_LOCALHOST;

SELECT * FROM DEPARTMENTS_1;
SELECT * FROM DEPARTMENTS_2;
SELECT * FROM DEPARTMENTS_3;
SELECT * FROM ALL_MVIEWS WHERE MVIEW_NAME LIKE 'DEPARTMENTS%';

查询数据字典,发现创建了一个刷新模式为DEMAND 刷新方式为FORCE 的物化视图DEPARTMENTS_1、DEPARTMENTS_2、DEPARTMENTS_3,且两个物化视图的数据量与基表一样。
同时基表所在库将基于departments的所有物化视图最后一次刷新时间记录在数据字典中DBA_BASE_TABLE_MVIEWS,内容如下

OWNER MASTER MVIEW_LAST_REFRESH_TIME MVIEW_ID
HR DEPARTMENTS 2019/1/9 16:07:01 51
HR DEPARTMENTS 2019/1/9 16:07:06 52
HR DEPARTMENTS 2019/1/9 16:07:12 53

可以分别与DEPARTMENTS_1、DEPARTMENTS_2、DEPARTMENTS_3相对应起来。
创建物化视图的标准语句详细见oracle 文档,常用语句结构如下:

CREATE MATERIALIZED VIEW [view_name] 
[ ON PREBUILT TABLE [ { WITH | WITHOUT } REDUCED PRECISION ] 
       | [BUILD { IMMEDIATE | DEFERRED }]    ]
[REFRESH [FAST|COMPLETE|FORCE] ]
[ ON COMMIT|DEMAND] 
[START WITH (start_time) NEXT (next_time) ]
[WITH {PRIMARY KEY | ROWID}]
[ { DISABLE | ENABLE } QUERY REWRITE]
AS subquery

关键字解读

  1. ON PREBUILT TABLE [ { WITH | WITHOUT } REDUCED PRECISION :指明是否通过现有同名同用户下表预创建物化视图,后面的参数表示 现有表的列与子查询返回的列精度不匹配时,是否降低精度,如果是指定了WITHOUT,但返回精度不匹配,将报错;当删除物化视图时不会删除同名表;
  2. BUILD { IMMEDIATE | DEFERRED }: 指明创建物化视图时生不生成数据,IMMEDIATE 表示立即生成,这是默认;DEFERRED表示创建时不生成数据,在第一次刷新时生成数据,且第一次刷新必须是完全刷新,在刷新之前物化视图不可用,因此不能指定查询重写子句;
  3. REFRESH 后的三个关键字[FAST|COMPLETE|FORCE] 表示物化视图的刷新方式:FAST表示快速增量刷新,刷新自上次刷新时间到当前时间的记录,需要物化视图日志;COMPLETE表示完全刷新,会删除物化视图中的所有记录,按照语句重新生成;FORCE表示满足快速刷新的条件就尽可能快速刷新,否则完全刷新;
  4. ON [COMMIT|DEMAND] 表示物化视图的两种刷新模式:ON COMMIT 表示基表一旦有了事务提交,就刷新数据,更新物化视图,该类物化视图增加基表提交所需时间;ON DEMAND表示手动刷新,可以在需要刷新数据时使用DBMS_MVIEW.REFRESH等方法来进行刷新;
  5. [START WITH (start_time) NEXT (next_time) ]:表示物化视图的刷新时间,第一组关键词START WITH指定的时间start_time表示第一次自动刷新时间NEXT指定的时间next_time表示下一次刷新时间,如果NEXT子句未指定,则只自动刷新一次;
  6. WITH {PRIMARY KEY | ROWID}:指定了创建的是主键物化视图还是ROWID物化视图;主键物化视图必须在查询子句中直接指定所有的主键列;ROWID物化视图用于查询子句未全部包含基表的主键列,同时ROWID物化视图有一些限制,如查询子句只能是单表查询,且不能包括Distinct、聚集函数、GROUP BY或CONNECT BY 子句、子查询、联接、set操作,ROWID的物化视图的基表如果重组了,那么在执行一次完全刷新之前,不能快速刷新;
  7. { DISABLE | ENABLE } QUERY REWRITE:指定物化视图是否能够应用于查询重写。查询重写有一些限制,比如物化视图中使用到的所有用户自定义函数都必须是DETERMINISTIC(可记住函数调用结果,对性能有好处);语句中的表达式都是可重复的,例如不能包含CURRENT_TIME或USER、序列值(例如CURRVAL或NEXTVAL伪列)或SAMPLE子句这种不可重复表达式;
3.向基表中插入一条数据,删除一条数据,修改一条数据,观察日志
--插入、删除和修改数据
INSERT INTO DEPARTMENTS(DEPARTMENT_ID,DEPARTMENT_NAME,MANAGER_ID,LOCATION_ID)
VALUES(0,'TEST',NULL,1700);
DELETE FROM DEPARTMENTS WHERE DEPARTMENT_ID=1;
UPDATE DEPARTMENTS SET MANAGER_ID=205 WHERE DEPARTMENT_ID=0;
--查询物化视图中的日志记录
select * from MLOG$_DEPARTMENTS;

插入、删除和修改基表之后,基表上的物化视图日志有内容,如下:

DEPARTMENT_ID SNAPTIME$$ DMLTYPE$$ OLD_NEW$$ CHANGE_VECTOR$$ XID$$
0 4000/1/1 I N FE 1688948644516339
1 4000/1/1 D O 00 1688948644516339
0 4000/1/1 U U 08 1688948644516339

对于物化视图的增量快速刷新来说,要实现对基表数据的同步,需要把基表上的变化信息记录下来,物化视图日志就是这个功能。
在基表上发生DML操作时,内部触发器会将变化信息记录到物化视图日志中,上表展示了对基表进行增删改之后,物化视图日志中记录的数据;
DEPARTMENT_ID:由于默认建立的是基于主键的物化视图日志,所以该列存储了DML操作影响到相关行的主键;
SNAPTIME$$:当DML操作发生后,该字段被填充为日期4000/1/1,表示这条记录还没有被任何物化视图刷新过。只在第一个物化视图(增量和全量)刷新这条记录时被修改
DMLTYPE$$:记录下了DML操作的类型,分别I(insert)、D(delete)、U(update),当修改字段为主键时,会用一组(I、D)插入删除操作代替U;
OLD_NEW$$:记录下了值的类型, insert对应N(NEW)、delete对应O(OLD)、update 对应 U(UPDATE);
CHANGE_VECTOR$$:存储以16进制数展示的RAW(255)类型数据,表示改变字段的位置映射,如修改操作对应的位置矢量08:二进制形式00001000表示,表示改变的列位于表的第三个位置,以此类推,如第一个位置表示为00000010、第二个位置表示为00000100、第一千个位置表示为00000001后面跟一千个0,二进制长度为1008,16进制长度为252;对于删除操作,该列值全为0,个数与列数有关;对于一般插入操作,该列值低位FE,高位补FF:FEFF…,个数与列数有关,对于修改主键而产生的插入操作,该列值全为FF,个数与列数有关;
XID$$:如果创建物化视图日志时指定了WITH COMMIT SCN,那么日志中就不再包含字段SNAPTIME$$而是记录了修改的XID信息,通过XID和SCN来判断一个物化视图是否需要刷新,由于SCN只能在本地用,所以不支持远程端的物化视图;

4.手动增量快速刷新物化视图departments_1
--快速增量刷新物化视图
BEGIN
  DBMS_MVIEW.refresh('DEPARTMENTS_1','F');
END;
--查询物化视图
SELECT * FROM DEPARTMENTS_1;

观察物化视图的数据,可以发现数据已经和基表同步了,再观察基表上的物化视图日志:

DEPARTMENT_ID SNAPTIME$$ DMLTYPE$$ OLD_NEW$$ CHANGE_VECTOR$$ XID$$
0 2019/1/9 16:24:23 I N FE 1688948644516339
1 2019/1/9 16:24:23 D O 00 1688948644516339
0 2019/1/9 16:24:23 U U 08 1688948644516339

以及物化视图的最后一次刷新时间:

OWNER MASTER MVIEW_LAST_REFRESH_TIME MVIEW_ID
HR DEPARTMENTS 2019/1/9 16:24:23 51
HR DEPARTMENTS 2019/1/9 16:07:06 52
HR DEPARTMENTS 2019/1/9 16:07:12 53

当刷新物化视图departments_1后,我们看到 日志中的SNAPTIME$$ 列被更新为刷新时间,且由于在此基表上还有物化视图departments_2没有刷新,所以物化视图中的日志没有被清除。

5.手动增量快速刷新物化视图departments_2
--快速增量刷新物化视图
BEGIN
  DBMS_MVIEW.refresh('DEPARTMENTS_2','F');
END;
--查询物化视图
SELECT * FROM DEPARTMENTS_2;

观察物化视图的数据,可以发现数据已经和基表同步了,再观察基表上的物化视图日志:

DEPARTMENT_ID SNAPTIME$$ DMLTYPE$$ OLD_NEW$$ CHANGE_VECTOR$$ XID$$
0 2019/1/9 16:24:23 I N FE 1688948644516339
1 2019/1/9 16:24:23 D O 00 1688948644516339
0 2019/1/9 16:24:23 U U 08 1688948644516339

以及物化视图的最后一次刷新时间:

OWNER MASTER MVIEW_LAST_REFRESH_TIME MVIEW_ID
HR DEPARTMENTS 2019/1/9 16:24:23 51
HR DEPARTMENTS 2019/1/9 16:32:36 52
HR DEPARTMENTS 2019/1/9 16:07:12 53

我们发现,物化视图日志中的的内容在2刷新之后没有删除,没有变化,只是最新的刷新时间被更新了

6.手动增量快速刷新物化视图departments_3
--快速增量刷新物化视图
BEGIN
  DBMS_MVIEW.refresh('DEPARTMENTS_3','F');
END;
--查询物化视图
SELECT * FROM DEPARTMENTS_3;

观察物化视图的数据,可以发现数据已经和基表同步了,
观察物化视图日志,发现记录被清空。
观察物化视图的最后一次刷新时间:

OWNER MASTER MVIEW_LAST_REFRESH_TIME MVIEW_ID
HR DEPARTMENTS 2019/1/9 16:24:23 51
HR DEPARTMENTS 2019/1/9 16:32:36 52
HR DEPARTMENTS 2019/1/9 16:38:51 53

发现最后物化视图3的最后一次刷新时间更新了。

现总结一下整个实验过程,以解决关于多个物化视图快速刷新时如何根据物化视图日志中的时间戳来确定要更新的记录以及物化视图日志中已经被所有物化视图刷新过的记录如何删除的问题:

  1. 在创建日志、创建物化视图之后做了增删改操作,数据库会将变化信息放入物化视图日志中,且三条记录的SNAPTIME都为4000/1/1;三个物化视图的最后一次刷新时间大约都是2019/1/9 16:07:06
  2. 在刷新1时,刷新记录的判断条件是SNAPTIME(4000/1/1)>LAST_FRESH_TIME(2019/1/9 16:07:06),日志中的三条记录全部被刷新,同时物化视图日志中的三条记录的SNAPTIME被置为2019/1/9 16:24:23,此时物化视图的最后一次刷新时间: 视图1 是2019/1/9 16:24:23,2和3没被刷新,还是原来的2019/1/9 16:07:06。尝试删除日志中的三条记录时判断条件SNAPTIME(2019/1/9 16:24:23)<=基表上所有物化视图的最后刷新时间(1:2019/1/9 16:24:23、2019/1/9 16:07:06 、2019/1/9 16:07:12):不符合条件,没删除日志
  3. 在刷新2时,刷新记录的判断条件是
    SNAPTIME(2019/1/9 16:24:23)>LAST_FRESH_TIME(2019/1/9 16:07:06),日志中的三条记录全部被刷新,日志中三条记录的SNAPTIME保持不变,此时物化视图的最后一次刷新时间:视图1 是2019/1/9 16:24:23,2是2019/1/9 16:32:36、3没被刷新,还是原来的2019/1/9 16:07:12。尝试删除日志中的三条记录时判断条件SNAPTIME(2019/1/9 16:24:23)<=基表上所有物化视图的最后刷新时间(1:2019/1/9 16:24:23、2019/1/9 16:32:36 、2019/1/9 16:07:12):不符合条件,没删除日志
  4. 在刷新3时,刷新记录的判断条件是
    SNAPTIME(2019/1/9 16:24:23)>LAST_FRESH_TIME(2019/1/9 16:07:12),日志中的三条记录全部被刷新,日志中三条记录的SNAPTIME保持不变,此时物化视图的最后一次刷新时间:视图1 是2019/1/9 16:24:23,2是2019/1/9 16:32:36、3是2019/1/9 16:38:51。尝试删除日志中的三条记录时判断条件SNAPTIME(2019/1/9 16:24:23)<=基表上所有物化视图的最后刷新时间(1:2019/1/9 16:24:23、2019/1/9 16:32:36 、2019/1/9 16:38:51 ):符合条件,删除了三条日志
5.删除物化视图和日志
--ORCL HR
DROP MATERIALIZED VIEW LOG ON DEPARTMENTS;
--ORCL1 SCOTT
DROP MATERIALIZED VIEW DEPARTMENTS_1;
DROP MATERIALIZED VIEW DEPARTMENTS_2;
6.注意事项

1.生产环境中创建物化视图时应明确指定查询列,避免基表结构改变导致物化视图失效;
2.主键物化视图的查询子句选用主键列时不能指定函数;
3.物化视图不能包含对LONG和LONG RAW数据类型的引用;
4.等等等。。。。。。。。,没怎么用过

你可能感兴趣的:(学习)