暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Oracle 实体化视图快速刷新与联接-什么工作是在哪里完成的?

askTom 2018-02-14
423

问题描述

如果我有两个表,都带有实体化视图日志,并且我将它们结合在一起,在一个快速的refrescable实体化视图中,当刷新该MV时,在哪里可以消除尚未删除的记录,但不应再由于MV中的谓词而返回?例如,我有一个带有日期的表,我将其加入到另一个表,其中col> date_table.date_column:

create table xxjk_master
as
select level id, date '2017-01-01' + mod(level,365) creation_date from dual connect by level <= 1000000;

alter table xxjk_master add constraint xxjk_master_pk primary key (id);

create table xxjk_date
as
select sysdate - 100 refresh_date from dual;

alter table xxjk_date add constraint xxjk_date primary key (refresh_date);

create materialized view log on xxjk_master with rowid;

create materialized view log on xxjk_date with rowid;

create materialized view xxjk_tst_mv 
refresh
on demand
fast
as
select i.rowid i_rid, d.rowid d_rid, i.id, i.creation_date from xxjk_master i, xxjk_date d
where i.creation_date > d.refresh_date;

select count(*) from  xxjk_tst_mv;
复制


我更新主表中的行,并按预期将它们进入MV日志。

insert into xxjk_master (id, creation_date) values (-1, sysdate);
insert into xxjk_master (id, creation_date) values (-2, sysdate-500);

select * from  MLOG$_XXJK_MASTER;

select * from  MLOG$_XXJK_DATE;
复制


我了解到,在快速刷新下,MV只是通过了这个增量。

exec dbms_mview.refresh(list=>'xxjk_tst_mv', method=>'F');

select count(*) from  xxjk_tst_mv;
复制


但是,如果我然后更新日期表中的日期,我会在MV日志中得到一行,但是我显然没有在xxmaster日志中得到任何一行,因为没有行被插入/更新/删除。

update xxjk_date set refresh_date = date '2017-12-31';

select * from  MLOG$_XXJK_MASTER;

select * from  MLOG$_XXJK_DATE;
复制


所以当我现在做一个刷新:

exec dbms_mview.refresh(list=>'xxjk_tst_mv', method=>'F');

select count(*) from  xxjk_tst_mv;
复制


Oracle在做什么来消除那些不再匹配谓词 “i.creation_date> d.refresh_date” 的行?

* 源表是否已完全扫描 (假设我在该列上没有索引),并应用了谓词并将行与MV进行比较?
* 是否应用谓词的逆以获取现在不需要的行的列表,然后将其从MV中删除?
* 是否将谓词应用于MV中的现有行以消除它们 (即,由于MV日志为空,甚至没有访问源主表?)
* 整个查询是否刚刚运行 (即根本不是快速刷新)
* 还有别的吗?

显然,如何在内部完成此操作可能会对刷新时间产生影响。如果我在我的主站点上有一百万行表,并且我正在复制说远程站点上只有最后5天 (5k行),那么如果使用上面的第三点,它将更加有效。或者,如果主站点被扫描,那么这是否与MV中的谓词一样完成将很重要-例如,我可能会在日期列上添加索引。

希望这有意义。附加了LiveSQL脚本。

谢谢,
约翰

专家解答

有一个简单的方法来找出:

跟踪会话!

alter session set tracefile_identifier = mv_refresh;
exec dbms_monitor.session_trace_enable(waits => true, binds => true);

exec dbms_mview.refresh(list=>'xxjk_tst_mv', method=>'F');

exec dbms_monitor.session_trace_disable();
复制


然后,您可以检查格式化的跟踪文件以获取要从XXJK_TST_MV中删除/插入的引用。

当运行您的示例时,我发现:

delete from "CHRIS"."XXJK_TST_MV" sna$
where "D_RID" in (
  select /*+ NO_MERGE  HASH_SJ  */ *
  from (
    select chartorowid( "MAS$"."M_ROW$$" ) rid$
    from "CHRIS"."MLOG$_XXJK_DATE" "MAS$"
    where "MAS$".snaptime$$ >:b_st0
    and   not (
      "MAS$".dmltype$$ = 'U'
      and   ( sys.dbms_snapshot_utl.vector_compare(:b_cv0,"MAS$".change_vector$$ ) = 0 )
    )
  ) as of snapshot (:b_scn ) mas$
);

Rows (1st) Rows (avg) Rows (max)  Row Source Operation
---------- ---------- ----------  ---------------------------------------------------
         0          0          0  DELETE  XXJK_TST_MV (cr=107 pr=0 pw=0 time=192262 us starts=1)
     15062      15062      15062   HASH JOIN RIGHT SEMI (cr=102 pr=0 pw=0 time=40491 us starts=1 cost=33 size=409572 card=1468)
         1          1          1    TABLE ACCESS FULL MLOG$_XXJK_DATE (cr=10 pr=0 pw=0 time=758 us starts=1 cost=6 size=269 card=1)
     15062      15062      15062    MAT_VIEW ACCESS FULL XXJK_TST_MV (cr=92 pr=0 pw=0 time=13815 us starts=1 cost=27 size=150610 card=15061)

insert  /*+ NOAPPEND */ into "CHRIS"."XXJK_TST_MV"
  select /*+ NO_MERGE("JV$") */ "MAS$1".rowid,
         "JV$"."RID$",
         "MAS$1"."ID",
         "MAS$1"."CREATION_DATE"
  from (
    select "MAS$"."ROWID" "RID$",
           "MAS$".*
    from "CHRIS"."XXJK_DATE" "MAS$"
    where rowid in (
      select  /*+ HASH_SJ */ chartorowid( "MAS$"."M_ROW$$" ) rid$
      from   "CHRIS"."MLOG$_XXJK_DATE" "MAS$"
      where  "MAS$".snaptime$$ >:b_st0
      and    not (
        "MAS$".dmltype$$ = 'U'
        and   ( sys.dbms_snapshot_utl.vector_compare(:b_cv0,"MAS$".change_vector$$ ) = 0 )
      )
    )
  ) as of snapshot (:b_scn ) "JV$",
        "XXJK_MASTER" as of snapshot (:b_scn ) "MAS$1"
  where "MAS$1"."CREATION_DATE" > "JV$"."REFRESH_DATE";

Rows (1st) Rows (avg) Rows (max)  Row Source Operation
---------- ---------- ----------  ---------------------------------------------------
         0          0          0  LOAD TABLE CONVENTIONAL  XXJK_TST_MV (cr=438 pr=0 pw=0 time=55929 us starts=1)
         1          1          1   NESTED LOOPS  (cr=438 pr=0 pw=0 time=55843 us starts=1 cost=271 size=509966 card=14999)
         1          1          1    VIEW  (cr=164 pr=0 pw=0 time=42835 us starts=1 cost=7 size=21 card=1)
         1          1          1     HASH JOIN SEMI (cr=164 pr=0 pw=0 time=42832 us starts=1 cost=7 size=277 card=1)
         1          1          1      INDEX FULL SCAN XXJK_DATE (cr=158 pr=0 pw=0 time=41893 us starts=1 cost=1 size=8 card=1)(object id 80954)
         1          1          1      TABLE ACCESS FULL MLOG$_XXJK_DATE (cr=6 pr=0 pw=0 time=629 us starts=1 cost=6 size=269 card=1)
         1          1          1    TABLE ACCESS FULL XXJK_MASTER (cr=274 pr=0 pw=0 time=12991 us starts=1 cost=264 size=194987 card=14999)
复制


我的MV里有15,062行。因此,数据库首先从其中删除所有内容。然后在有效行中插入。

我们没有记录这个过程,所以你可能会发现不同版本的差异。无论如何,一旦有了刷新SQL,您就可以查看是否可以做些什么来改进它。请记住,您无法更改它,它可能会更改!
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论