物化视图日志的维护

简介: 物化视图日志经常会由于物化视图长时间没有刷新,或者基表的一次批量数据更改而变得很大,这会影响物化视图的刷新性能,因此对于这种情况需要对物化视图日志进行处理,降低物化视图日志表的高水位线。

物化视图日志经常会由于物化视图长时间没有刷新,或者基表的一次批量数据更改而变得很大,这会影响物化视图的刷新性能,因此对于这种情况需要对物化视图日志进行处理,降低物化视图日志表的高水位线。

 

 

Oracle的物化视图的快速刷新功能,主要是靠物化视图日志来实现的。

物化视图日志会记录下基表所有的增、删、改操作,而物化视图执行完快速刷新操作后,会从物化视图日志中将本物化视图刷新过且其他物化视图所不需要刷新的记录删除掉。如果其中一个物化视图一直不刷新,那么物化视图日志就会变得越来越大。

还有一种情况,比如表中插入了大量的数据,或者删除了大量的数据,或者将表中的某一列统一更新为一个值,这种操作都会在物化视图日志中产生大量的记录。

而物化视图日志的增大必然影响物化视图的刷新速度。一方面,物化视图在刷新的时候要扫描物化视图日志,另一方面,物化视图在刷新介绍后,也要清除物化视图日志中的记录,仍然要扫描物化视图日志,因此物化视图日志的大小直接会影响物化视图快速刷新的速度。更重要的是,物化视图日志的高水位一旦增长到一个很高的位置,即使以后物化视图日志中记录很少,甚至没有记录存在,物化视图在刷新的时候仍然需要较长的时间。

因此,在对于物化视图的基表进行操作时,应注意尽量更新需要更新的记录:

SQL> CREATE TABLE T (ID NUMBER PRIMARY KEY, NAME VARCHAR2(30));

表已创建。

SQL> INSERT INTO T SELECT ROWNUM, OBJECT_NAME FROM DBA_OBJECTS;

已创建50674行。

SQL> CREATE MATERIALIZED VIEW LOG ON T;

实体化视图日志已创建。

用一个最简单的例子来说明什么叫做更新需要更新的记录。现在需要将T表中的NAME字段全部用大写来表示,最简单的写法:

SQL> UPDATE T SET NAME = UPPER(NAME);

已更新50674行。

SQL> SELECT COUNT(*) FROM MLOG$_T;

  COUNT(*)
----------
     50674

SQL> ROLLBACK;

回退已完成。

但是这种写法就会造成一些没有必要更新的记录也执行了更新操作,从而导致物化视图日志中记录了很多没有必要刷新的记录,这些记录不但影响物化视图日志的高水位线,而且会增加物化视图刷新的成本。

对于物化视图的基表,这个刷新则应该改写为:

SQL> UPDATE T SET NAME = UPPER(NAME) WHERE NAME != UPPER(NAME);

已更新34007行。

SQL> SELECT COUNT(*) FROM MLOG$_T;

  COUNT(*)
----------
     34007

采用这种方式就可以避免刷新不必要的列而使得物化视图日志变得很大。

不过有的时候大数据量的操作无可避免,或者物化视图日志本身已经变得很大,已经开始影响物化视图的刷新性能了,那么就只能通过维护物化视图日志表的方式来降低高水位线。

不应该对物化视图日志执行TRUNCATE TABLE操作。因为即使查询物化视图日志表中不存在记录,也无法确保在执行TRUNCATE TABLE操作之前,没有其他会话修改物化视图基表,从而导致新的记录插入物化视图日志中。

一旦发生物化视图日志记录被TRUNCATE的情况,就会导致物化视图和物化视图基表的数据不一致。例如:

SQL> CREATE MATERIALIZED VIEW MV_T REFRESH FAST AS SELECT * FROM T;

实体化视图已创建。

SQL> INSERT INTO T VALUES (60000, 'A');

已创建 1 行。

SQL> TRUNCATE TABLE MLOG$_T;

表被截断。

SQL> INSERT INTO T VALUES (60001, 'B');

已创建 1 行。

SQL> EXEC DBMS_MVIEW.REFRESH('MV_T')

PL/SQL 过程已成功完成。

SQL> SELECT * FROM MV_T WHERE ID >= 60000;

        ID NAME
---------- ------------------------------
     60001 B

即使采用LOCK表的方式配合TRUNCATE,也无法避免并发的问题。

尝试在TRUNCATE之前LOCK物化视图日志表,很可能在TRUNCATE操作的时候失败:

SQL> LOCK TABLE MLOG$_T IN EXCLUSIVE MODE;

表已锁定。

会话1锁定物化视图日志表,这时会话2插入基表一条记录:

SQL> SET SQLP 'SQL2> '
SQL2> INSERT INTO T VALUES (60002, 'C');

会话1执行TRUNCATE语句:

SQL> TRUNCATE TABLE MLOG$_T;
TRUNCATE TABLE MLOG$_T
               *
第 1 行出现错误:
ORA-00054: 资源正忙, 但指定以 NOWAIT 方式获取资源

会话2成功插入记录:


已创建 1 行。

SQL2> SELECT ID FROM MLOG$_T;

        ID
----------
     60002

这是由于会话1执行TRUNCATE操作,会先发出一个COMMIT,从而释放了MLOG$_T上的锁,而这时会话2获得了MLOG$_T上的锁,并插入记录。由于会话2获得了物化视图日志上的锁,会话1尝试TRUNCATE就会失败。

如果尝试在基表上加锁,虽然可以避免基表的修改造成的物化视图日志改变,但是无法避免手工修改物化视图日志表的情况,虽然这种情况基本上不会发生。

因此处理物化视图高水位线最稳妥的方法还是使用MOVE的方式。

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
29天前
|
存储 数据库
ALTER MATERIALIZED VIEW LOG :语句来更改现有物化视图日志的存储特征或类型。
`ALTER MATERIALIZED VIEW LOG` 语句用于修改已有的物化视图日志的存储属性或类型。配合示例中的动画图像(由于格式限制无法显示),该语句帮助优化数据库的性能和管理。
44 0
|
Oracle 关系型数据库 数据库
Oracle 物化视图和物化视图日志
物化视图是将查询预先定义在结构中,并手动或者定期刷新将结果存储在物化视图段中,也就是说跟普通视图不同,它是需要存储空间的,从而不需要重新或者反复的执行sql语句,支持增量刷新,快速获取结果,提高数据获取的效率。
3331 0
|
SQL 监控 Oracle
物化视图刷新失败导致日志表异常增大
整理自:http://blog.itpub.net/231499/viewspace-63714/ 今天在检查时,发现某个物化视图日志占用的空间超过150M,再检查看,该物化视图日志表的记录数有150W,由于其对应的物化视图没有会刷新一次,结合业务量分析可知:物化视图日志不能正常清除。
1388 0
|
监控 Oracle 关系型数据库
物化视图的快速刷新测试与物化视图日志
前言:一般在创建物化视图的时候,在数据量不大的时候,刷新的方式都是采用完全刷新的。随着系统的使用一些物化视图的源表的数据量在不断的增长,原本采用完全方式几秒就能刷新完成的物化视图,现在需要等待很久的时间才能刷新完成。
1162 0
|
SQL Perl
物化视图导出导入可能导致物化视图日志的失效
SQL> create user yang identified by yang;用户已创建。已用时间:  00: 00: 00.10SQL> grant resource,connect to yang;授权成功。
729 0
|
17天前
|
Java
使用Java代码打印log日志
使用Java代码打印log日志
73 1
|
18天前
|
Linux Shell
Linux手动清理Linux脚本日志定时清理日志和log文件执行表达式
Linux手动清理Linux脚本日志定时清理日志和log文件执行表达式
72 1