物化视图快速刷新-更新基表时插入和删除

kov*_*sue 4 oracle plsql oracle19c

大家好,Stackoverflowers 的朋友们,

TLDR:MVIEW 是否正在使用UPDATEDELETE + INSERT在刷新期间?

前一段时间,当我在 Oracle 中摆弄物化视图时,遇到了一件晦涩难懂的事情。这是我的例子:

  • 2 个基表
  • 两个表的 MVIEW 日志
  • 两张桌子的PK
  • MVIEW 创建为这些基表的联接
  • MVIEW PK

这是一个示例代码:

-- ========================= DDL section =========================

/* drop tables */
drop table tko_mview_test_tb;
drop table tko_mview_test2_tb;

/* drop mview */
drop materialized view tko_mview_test_mv;

/* create tables */
create table tko_mview_test_tb as
  select 1111 as id, 'test' as code, 'hello world' as data, sysdate as timestamp from dual
  union
 select 2222, 'test2' as code, 'foo bar', sysdate - 1 from dual; 
 
create table tko_mview_test2_tb as
  select 1000 as id, 'test' as fk, 'some string' as data, sysdate as timestamp from dual;

/* create table PKs */  
alter table tko_mview_test_tb
  add constraint mview_test_pk
  primary key (id);

alter table tko_mview_test2_tb
  add constraint mview_test2_pk
  primary key (id);

/* create mview logs */
create materialized view log
  on tko_mview_test_tb
  with rowid, (data);
  
create materialized view log
  on tko_mview_test2_tb
  with rowid, (data);
  
/* create mview */
create materialized view tko_mview_test_mv
refresh fast on commit
as select a.code
        , a.data
        , b.data as data_b
        , a.rowid as rowid_a
        , b.rowid as rowid_b 
     from tko_mview_test_tb a
       join tko_mview_test2_tb b on b.fk = a.code;

/* create mview PK */ 
alter table tko_mview_test_mv
  add constraint mview_test3_pk
  primary key (code);    
Run Code Online (Sandbox Code Playgroud)

根据dbms_mview.explain_mview我的MVIEW是否能够快速刷新。

在这种特殊情况下(此处未举例),MVIEW 由其他表中的 FK 引用。因此,我发现,当我对这些基表之一进行更改并触发 MVIEW 刷新时,我收到一条错误消息:

ORA-12048: error encountered while refreshing materialized view "ABC"
ORA-02292: integrity constraint (ABC_FK) violated
Run Code Online (Sandbox Code Playgroud)

我当时想什么鬼?。所以我开始挖掘 - 我在 MVIEW 上创建了一个触发器。像这样的东西:

ORA-12048: error encountered while refreshing materialized view "ABC"
ORA-02292: integrity constraint (ABC_FK) violated
Run Code Online (Sandbox Code Playgroud)

所以我能够看到发生了什么。根据我的触发器,每次我在基表中执行UPDATE (不是 INSERT 或 DELETE)时,实际上都会对 MVIEW 表进行DELETE 和 INSERT操作。

/* create trigger on MVIEW */  
create or replace trigger tko_test_mview_trg
  after insert or update or delete
  on tko_mview_test_mv
  referencing old as o new as n
  for each row
declare
begin
  if updating then
    dbms_output.put_line('update');
  elsif inserting then
    dbms_output.put_line('insert');
  elsif deleting then
    dbms_output.put_line('delete');
  end if;  
end tko_test_mview_trg;
/
Run Code Online (Sandbox Code Playgroud)

输出

delete
insert
Run Code Online (Sandbox Code Playgroud)

这是 MVIEW 刷新的正确工作方式吗?刷新MVIEW时MVIEW表没有更新?

问候,汤姆

小智 5

从 oracle 12.1 升级到 oracle 19.x 后我们看到了相同的行为

新创建的 mview 似乎表现相同,在刷新期间删除/插入,而不是“预期”更新。不确定它是坏还是错......但它可以“修复”。

应用补丁 30781970(不要忘记 _fix_control)并重新创建 mview......

参考:Bug 30781970 - MVIEW 刷新因 MVIEW 上存在触发器而出现 ORA-1 错误而失败(文档 ID 30781970.8)