【问题标题】:How to catch errors when refresh nested materialized views刷新嵌套物化视图时如何捕获错误
【发布时间】:2019-08-23 19:55:16
【问题描述】:

物化视图“MV_AMP”:

CREATE MATERIALIZED VIEW MV_AMP
  NOLOGGING
  BUILD IMMEDIATE
  REFRESH FORCE
  ON DEMAND
AS
Select a, b, c from amp;

依赖于“MV_AMP”的物化视图“MV_BOT”:

CREATE MATERIALIZED VIEW MV_BOT
  NOLOGGING
  BUILD IMMEDIATE
  REFRESH FORCE
  ON DEMAND
AS
SELECT bot.x, bot.y, mv_amp 
FROM bot, mv_amp
WHERE bot.a = mv_amp.a;

并在 mv_bot 中创建唯一索引:

CREATE UNIQUE INDEX mv_bot_idx001 ON mv_bot(x, a);

视图和索引创建成功后,假设我添加了一个重复值,由于唯一索引刷新 mv_bot 时会导致 (dup_val_on_index) 之类的错误。

所以我在 MV_AMP(主视图)中使用 nested=TRUE 进行了刷新,Oracle 没有引发错误:

BEGIN
  dbms_mview.refresh_dependent(number_of_failures => n_failures,
                                   list => 'MV_AMP',
                                   atomic_refresh => TRUE,
                                   nested => TRUE);

EXCEPTION
  WHEN
    OTHERS THEN
        -- it never reach this code
        dbms_output.put_line('Errors: '||SQLERRM);
END;

n_failures 返回:0 并且它永远不会到达异常内部的 dbms_output。

当 oracle 尝试更新嵌套的 MV 并登录表时,我需要捕获错误。

使用 Oracle 11g。

【问题讨论】:

    标签: oracle materialized-views


    【解决方案1】:

    只有在物化视图MV_BOT 中存在重复行的情况下才会到达EXCEPTION 块 - 情况并非如此。

    你可能会问为什么;最可能的答案是您还需要刷新物化视图MV_AMP才能获得MV_BOT 的连接中的副本。

    在阅读 dbms_mview.refresh_dependent 的文档时,您意识到,您必须从表 AMP 开始刷新两个 MV(从 MV_AMP 开始只刷新 依赖的 MV MV_BOT )

    测试用例

    create table amp (
    a number,
    b number,
    c number);
    
    create table bot (
    a number,
    x number,
    y number);
    
    CREATE MATERIALIZED VIEW MV_AMP
      NOLOGGING
      BUILD IMMEDIATE
      REFRESH FORCE
      ON DEMAND
    AS
    Select a, b, c from amp;
    
    CREATE MATERIALIZED VIEW MV_BOT
      NOLOGGING
      BUILD IMMEDIATE
      REFRESH FORCE
      ON DEMAND
    AS
    SELECT bot.x, bot.y, mv_amp.a 
    FROM bot, mv_amp
    WHERE bot.a = mv_amp.a;
    
    CREATE UNIQUE INDEX mv_bot_idx001 ON mv_bot(x, a);
    
    insert into amp(a,b,c) values(1,1,1);
    insert into bot(a,x,y) values(1,1,1);
    insert into bot(a,x,y) values(1,1,3);
    commit;
    
    DECLARE
      n_failures NUMBER;
    BEGIN
      dbms_mview.refresh_dependent(number_of_failures => n_failures,
                                       list => 'AMP',
                                       atomic_refresh => TRUE,
                                       nested => TRUE);
       dbms_output.put_line('Failures: '||n_failures);                                                                
    EXCEPTION
      WHEN
        OTHERS THEN
            dbms_output.put_line('Errors: '||SQLERRM);
    END;
    /
    
    --> Errors: ORA-12008: error in materialized view refresh path
    --> ORA-00001: unique constraint (xxxxx.MV_BOT_IDX001) violated
    

    【讨论】:

    • 也许我的例子并没有完全解释这个问题。请忽略示例表中提供的值,仅考虑这 2 个 MV,MV_BOT 取决于 MV_AMP。在实际场景中,重复行出现在 MV_BOT 中,因为它与导致这种情况的其他表连接。如果我不使用“MV_AMP”开始刷新,我怎么知道这个视图的主表?在实际场景中,它有一个包含 3 或 4 个不同表的选择。
    • @Joel 我的意思是换句话说——你刷新 PL/SQL 只刷新 MV_BOT 并保持 MV_APP 不变。您必须选择MV_APP(此处为APP)的某个来源作为刷新两个MV的起点。
    • 尝试使用来自 MV_AMP 的主表启动 dbms_mview.refresh_dependent,但不幸的是得到了相同的结果。 MV_BOT 由于索引上的重复值没有更新,并且刷新过程没有引发任何错误。
    • @Joel 我添加了一个触发unique constraintexception 的可重现示例。您可以尝试概括您的里程。另请注意,在您的MV_BOT DDL 中是一个语法错误,我使用mv_amp.a 而不是mv_amp 修复了它 - 希望这只是错字。
    猜你喜欢
    • 2011-01-10
    • 1970-01-01
    • 2012-07-18
    • 1970-01-01
    • 2011-07-09
    • 2010-09-27
    • 2013-12-04
    • 1970-01-01
    • 2017-06-15
    相关资源
    最近更新 更多