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(30)
 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操作发生在那个或那几个字段上。

当刷新物化视图时,只需要根据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> insert 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 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 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$$列小于所有物化视图的上次刷新时间的记录,而这些记录已经被所有的物化视图都刷新过了,保存在物化视图日志中已经没有意义了。

Oracle 如何根据物化视图日志快速刷新物化视图 (不积跬步,无以至千里)相关推荐

  1. Oracle ORA-12154: TNS:could not resolve the connect identifier specified(不积跬步,无以至千里)

    ORA-12154: TNS:could not resolve the connect identifier specified 在网上也找了些方法,但没有解决我的问题. 之前sql环境同步里是: ...

  2. oracle左补全函数,Oracle 左侧补齐函数lpad 函数 (不积跬步,无以至千里)

    Oracle 左侧补齐函数lpad 函数 (不积跬步,无以至千里) (2017-10-08 16:24:41) 函数介绍 lpad函数从左边对字符串使用指定的字符进行填充.从其字面意思也可以理解,l是 ...

  3. Oracle 常见问题1000问(不积跬步,无以至千里)

    1. Oracle 安装完成后的初始口令? internal/oracle sys/change_on_install system/manager scott/tiger sysman/oem_te ...

  4. Oracle 导出数据库(不积跬步,无以至千里)

    exp 帐号/密码 file=D:\1.dmp log=D:\exp.log 在数据库服务器上用管理员执行cmd命令. 以上语句20140430证实会有问题 在Oracle 11g中 该命令不会导出空 ...

  5. Oracle数据库还原dmp文件 (不积跬步,无以至千里)

    C:\Documents and Settings\hb>imp system/****** file=E:\DB\chb.dmp full=y ignore=y Import: Release ...

  6. oracle左补全函数,Oracle 左侧补齐函数lpad 函数 (不积跬步,无以至千里)

    函数介绍 lpad函数从左边对字符串使用指定的字符进行填充.从其字面意思也可以理解,l是left的简写,pad是填充的意思,所以lpad就是从左边填充的意思. 编辑本段语法 语法格式如下: lpad( ...

  7. oracle12c视图刷新,12c 物化视图 - 对快速刷新的理解

    前一篇博客用一个简单的示例描述了完全刷新的物化视图.完全刷新的物化视图每次刷新都需要对保存数据的基表执行delete操作,在将新的结果集insert到基表.为了减少这个开销,为了减少这个开销Oracl ...

  8. 定位导致物化视图无法快速刷新的原因

    转载自:http://yangtingkun.itpub.net/post/468/13318 物化视图的快速刷新采用了增量的机制,在刷新时,只针对基表上发生变化的数据进行刷新.因此快速刷新是物化视图 ...

  9. 刷新物化视图很慢_快速刷新物化视图

    确认当前操作的实例名 select instance_name,status from v$instance; select instance_name,status from gv$instance ...

最新文章

  1. Pytorch之深入理解torch.nn.Parameter()
  2. Windows Server 2016 + Exchange 2016 +Office365混合部署(四)
  3. 将新更新从原始GitHub存储库中提取到派生的GitHub存储库中
  4. OpenCV各个模块/各个文件夹的含义
  5. 如何获得Java中泛型类的类型参数?
  6. 数据库操作之增删改查CRUD
  7. Python3.6全栈开发实例[006]
  8. CF-1207 F. Remainder Problem(分块)
  9. HihoCoder - 1873 Frog and Portal(构造+进制拆分)
  10. 计算机图形图像项目教程素材,案例任务驱动法在图形图像教学中的运用
  11. ADODB.Stream
  12. 电动48V/60V自行车/摩托车/观光车电池检测设备,满足GB38031新国标测试
  13. 使用Html.fromHtml()怎么加载Html中的图片
  14. 大学生用什么软件学c语言,当代大学生必须的几款APP
  15. Hive 练习(带数据)
  16. 远程服务器返回错误码: (507) Insufficient Storage
  17. cinder(cinderella怎么读英语)
  18. 忘记linux里mysql账号密码忘记_Linux下MySQL忘记root用户密码
  19. 系统可靠性设计(系统架构师)
  20. 如何判断是手机端还是PC端?

热门文章

  1. Google Earth Engine(GEE)——在GEE上画出论文研究区图(彩色)
  2. 加州伯克利本科学计算机好吗,加州大学伯克利分校计算机科学专业详解!
  3. 【资料】wod地城掉落
  4. Android 自定义DatePick 只显示年月,日期选择年月
  5. 机器学习模型的集成方法总结:Bagging, Boosting, Stacking, Voting, Blending
  6. 您如何在没有“经验”的情况下开始在其他领域的职业-这些技巧为我提供了工作机会…...
  7. 项目管理(PMP)精选题精讲
  8. C++ 堆区,栈区,数据段,bss段,代码区(详解)
  9. 练习之彩票三 添加号码相关代码
  10. Strlen和Sizeof的区别