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

Posted

技术标签:

【中文标题】物化视图快速刷新 - 更新基表时插入和删除【英文标题】:Materialized view fast refresh - insert and delete when updating base table 【发布时间】:2021-01-09 07:55:28 【问题描述】:

大家好,***ers,

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

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

2 个基表 两个表的 MVIEW 日志 两个表的 PKs 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);    

根据dbms_mview.explain_mview我的MVIEW,如果能够快速刷新。

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

ORA-12048: error encountered while refreshing materialized view "ABC"
ORA-02292: integrity constraint (ABC_FK) violated

我当时想这到底是怎么回事??。所以我开始挖掘——我在那个 MVIEW 上创建了一个触发器。像这样的:

/* 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;
/

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

update tko_mview_test2_tb
   set data = 'some sting'
 where id = 1000; 
commit;

输出

delete
insert

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

问候, 汤姆

【问题讨论】:

刷新可以使用这样的方法。尝试在 MVIEW 上使用延迟约束,可能会起作用(我没有尝试过) 嗨@gsalem,创建引用MVIEW的FK约束将无济于事。我已经试过了。该解决方案的问题是,当我进行更改时,约束检查延迟到事务结束(基本上提交),但 MVIEW 在提交时刷新。所以刷新 MVIEW 是新事务。 可能发生的事情是提交的开始将 FK 标记为“待检查”。 codefk 在基表中都没有被限制为unique 时,为什么要将code 定义为MV 的PK? 这只是一个示例代码。我在编写此示例代码时检查了唯一性。但这绝对与我在 MVIEW 刷新期间有关 DML 的问题无关。其实MVIEW上根本不需要这个PK。 【参考方案1】:

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

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

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

参考:错误 30781970 - MVIEW REFRESH 失败并出现 ORA-1 错误,MVIEW 上存在触发器(文档 ID 30781970.8)

【讨论】:

以上是关于物化视图快速刷新 - 更新基表时插入和删除的主要内容,如果未能解决你的问题,请参考以下文章

红移物化视图刷新是不是会锁定基表?

oracle物化视图不会自动更新是怎么回事

Oracle-视图

解决oracle 物化视图刷新失败

Oracle设置物化视图的自动刷新

PG 物化视图