Oracle:物化视图快速刷新原子?

时间:2015-04-08 11:00:51

标签: oracle atomic materialized-views

过去几个小时我已经阅读了很多关于在Oracle中刷新MV的内容,但我仍然无法找到问题的答案。想象一下,我在一个带有更改日志的表顶部有一个MV视图。所以这个MV中有三条记录:

COL_ID, COL1
1, "OLD"
2, "OLD"
3, "OLD"

现在假设COL1的值已更改为“EDITED”,表示用于创建MV的表中的记录1。我想执行快速就地刷新以尽快更新MV。在具有大约50M记录的现实生活中,这将花费大约3分钟来刷新。

想象一下情况。

  1. 刷新过程仍在运行(MV中仍有未修改的记录)。
  2. Neverthelss,已经处理了ID = 1的记录,因此它在MV中的值为“EDITED”。
  3. 在另一个会话中,执行对MV的查询以获取ID = 1的记录值。
  4. 结果会记录值“OLD”或“EDITED”吗?

    我理解,因为这是刷新机制处理此记录后的就地刷新,物化视图中的值将反映原始表中的值(“EDITED”)。但有没有任何机制(如撤消日志)会使整个刷新原子?我的意思是,除非对物化视图进行所有修改(除非刷新过程完成),否则如果用户查询在刷新过程中已经修改的行,他/她将被呈现给旧的,缓存价值 - 改变之前。

    我认为这个bevahiour对于不合适的刷新是正确的,但是由于前者似乎在时间消耗方面更有效,我很好奇这对于就地转换是否也是如此。 如果不是默认情况下,有没有办法强制这种原子行为?

    ----- [编辑]

    我在测试后运行测试,看看在刷新过程中我从物化视图中得到的结果是否会逐渐变化。

    -- create table
    create table MV_REFRESH_ATOMICITY_TEST
    (
      id    NUMBER,
      value NUMBER
    )
    
    -- populate initial data
    -- delete from MV_REFRESH_ATOMICITY_TEST
    declare
    begin
       for i in 1..10000000  loop
           insert into MV_REFRESH_ATOMICITY_TEST values(i, 0);
       end loop;  
    end;
    
    -- check if equal zero and 1M
    select sum(value) from MV_REFRESH_ATOMICITY_TEST
    select to_char(count(*),'999,999,999') as COUNT from MV_REFRESH_ATOMICITY_TEST       
    
    -- create mv logs on the table
    -- drop materialized view log on MV_REFRESH_ATOMICITY_TEST;     
    create materialized view log on MV_REFRESH_ATOMICITY_TEST with rowid;     
    
    -- create mv on top
    -- drop materialized view MV_REFRESH_ATOMICITY_TEST_MV
    create materialized view MV_REFRESH_ATOMICITY_TEST_MV
    refresh fast on demand with rowid
    as
    select
           fact.*,
           fact.ROWID "FACT_ROWID"
    from
           MV_REFRESH_ATOMICITY_TEST fact
    
    -- check if equals zero and 10M
    select sum(value) from MV_REFRESH_ATOMICITY_TEST_MV       
    select to_char(count(*),'999,999,999') as COUNT from MV_REFRESH_ATOMICITY_TEST_MV     
    
    -- change value for first million records, 1 milion records in the middle, last milion of records
    update MV_REFRESH_ATOMICITY_TEST set value = 1 where id between 1 and 1000000
    update MV_REFRESH_ATOMICITY_TEST set value = 1 where id between 5000001 and 6000000
    update MV_REFRESH_ATOMICITY_TEST set value = 1 where id between 9000001 and 10000000
    
    -- check if equals 3.000.000
    select to_char(sum(value),'999,999,999') as "SUM" from MV_REFRESH_ATOMICITY_TEST
    
    -- check if equals 3.000.000
    select to_char(count(*),'999,999,999') from MLOG$_MV_REFRESH_ATOMICITY;  
    --select * from MLOG$_MV_REFRESH_ATOMICITY;
    
    -- while refreshing mv
    -- exec dbms_mview.refresh('MV_REFRESH_ATOMICITY_TEST_MV', 'F');
    -- below sum should be equal 0
    select 
       ( select sum(value) from MV_REFRESH_ATOMICITY_TEST_MV ) "SUM",
       ( select count(*) from MV_REFRESH_ATOMICITY_TEST_MV ) "NUMBER OF RECORDS"  
    from dual
    

    所以我通过不断执行最后一个select语句发现的是,SUM值发生变化的唯一时间,它已经被3M更改,这意味着所有记录都已经一次性更改 - 原子。

    尽管如此,我并不是100%肯定我可以相信这个实验,因为在某些时候执行这些选择查询需要大约40秒。整个刷新语句需要911秒才能执行。

    [编辑]

    此问题已标记为this thread的可能副本。另一个线程确实响应了类似的问题,但是对于完全刷新,我的理解是以与快速刷新完全不同的方式执行,这就是这里的情况。因此,我不确定这里是否可以应用相同的解释。

1 个答案:

答案 0 :(得分:2)

从Oracle文档(http://docs.oracle.com/cd/B19306_01/server.102/b14226/repmview.htm#i31171)可以看出 - 所有刷新都是以原子方式完成的:

  

物化视图的数据不一定与其主表或主物化视图的当前数据匹配。物化视图是其主数据的事务(读)一致反映,因为数据存在于特定时间点(即创建时或刷新时)。

Oracle为物化视图组提供了更高的读取一致性:

  

为了保持多个物化视图之间的参照完整性和事务性(读取)一致性,Oracle能够刷新单个物化视图作为刷新组的一部分。刷新刷新组中的所有物化视图后,组中所有物化视图的数据对应于事务上一致的相同时间点。