物化视图快速刷新 - 更新基表时插入和删除
Posted
技术标签:
【中文标题】物化视图快速刷新 - 更新基表时插入和删除【英文标题】:Materialized view fast refresh - insert and delete when updating base table 【发布时间】:2021-01-09 07:55:28 【问题描述】:大家好,***ers,
TLDR:MVIEW 在刷新期间是否使用UPDATE
或DELETE + 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 标记为“待检查”。 当code
和fk
在基表中都没有被限制为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)
【讨论】:
以上是关于物化视图快速刷新 - 更新基表时插入和删除的主要内容,如果未能解决你的问题,请参考以下文章