链接服务器上的 Oracle 物化视图 table

Oracle Materialized View on linked server table

我试图在链接服务器 table 上用 refresh on commit 创建 Materialized view,但到目前为止没有成功。也不确定这是否可能,因为在 oracle 文档中,它没有说这是否可能。

我可以使用 refresh fast/complete 创建正常的物化视图,但我无法使用 on commit。据我从文档中了解到,我需要创建 MATERIALIZED VIEW LOG ON "table_name",但 Oracle 不允许我将此 table 指向链接的

我试过的代码:

CREATE MATERIALIZED VIEW LOG ON (SCHEMA_NAME.TABLE_NAME@DATABASE_LINK1)
WITH ROWID (col1, col2, col3, col4, col5),
INCLUDING NEW VALUES;

后一个有效,如果我将 REFRESH FAST 更改为 REFRESH NEXT TRUNC(SYSDATE) + 1

CREATE MATERIALIZED VIEW MYSCHEME_NAME.TABLE_NAME
BUILD IMMEDIATE
REFRESH FAST ON COMMIT
  AS SELECT col1, col2, col3, col4, col5
  FROM SCHEMA_NAME.TABLE_NAME@DATABASE_LINK1;

也许有人可以建议另一种方法?

我不能使用正常的 VIEWS,因为它们太慢了,但我希望数据尽可能地更新,所以在最坏的情况下,我只会使用 REFRESH NEXT TRUNC(SYSDATE) + 1虽然我不喜欢无缘无故刷新视图的想法。

编辑:我刚刚在下面添加了连续查询通知选项

我明白你的意思,但考虑到你同时谈论两个不同的数据库,它看起来更像是 almost-real-time 数据复制的问题。

在数据库 A 上,您的数据一旦提交,就必须在数据库 B 上进行复制(稍作转换,例如减少列数)。

Oracle 流

您可能可以看看 Streams(针对复制问题量身定制),例如从这里开始:Simple Single-Source Replication Example。就其本质而言,使用 Streams 只会在提交时复制更改,而不是更早。
不过,这可能有点矫枉过正,因为尽管标题中有 "Simple",但您会发现 "simple" 示例相当长。
如果您要那样做,还请查看 Managing Rule-Based Transformations,以在复制期间转换数据。

定期刷新视图

要刷新视图,您可以定义一个 job。为了每天刷新它,但仅当 table 发生变化时,您可以跟踪 table 的最新 SCN(一个告诉 [=59= 版本的标记) ]) 和(每天)刷新您的视图,但前提是最新的 SCN 已更改(这很丑陋,有点像穷人的复制)。所有这些 'refresh' 逻辑都应该放在作业的 body.

--example of how to select the most current SCN
select MAX(ora_rowscn) from SCHEMA_NAME.TABLE_NAME@DATABASE_LINK1;

--example of how to submit a job executed on a daily basis
exec dbms_job.submit(:v_JobNo,
  'a string representing the PL/SQL logic that refreshes the view only when the scn has changed',
  TRUNC(SYSDATE)+1,
  'TRUNC(SYSDATE)+1'
);

使用连续查询通知

CQN 允许定义在查询结果更改时调用的回调(参见 ORACLE-BASE - DBMS_CHANGE_NOTIFICATION in Oracle 10g Database Release 2)。您可以在远程数据库上使用它来在添加新记录时触发本地数据库视图的刷新。
试一试,因为我不确定远程数据库上的通知是否可以触发驻留在不同数据库(本地数据库)上的回调过程。

这是我会使用的代码类型(并根据我的需要进行调整;例如,查询中的 COUNT(*) 有效但性能很糟糕)

在本地数据库上定义您的视图和刷新后者的过程。相同的过程将作为远程数据库上的回调调用。

drop procedure refresh_materialized_view;
drop materialized view mat_view;

create materialized view mat_view
as select * from monitored_table@remote_db;
/


--this local procedure refreshes the view
create or replace procedure refresh_materialized_view is
begin
  --C stands for Complete refresh
  DBMS_SNAPSHOT.REFRESH( 'MAT_VIEW','C'); 
end;
/

在远程数据库上注册更改通知以调用上面定义的回调。注意权限,您可能需要 grant change notification 到此数据库上的正确用户

create table monitored_table(n number, ts timestamp);
insert into monitored_table values(1, systimestamp);
commit;



DECLARE
  l_regds     SYS.CHNF$_REG_INFO;
  l_regid     NUMBER;
  l_qosflags  NUMBER;
  v_n        monitored_table.n%TYPE;
BEGIN
  l_qosflags := DBMS_CHANGE_NOTIFICATION.QOS_RELIABLE  +
                DBMS_CHANGE_NOTIFICATION.QOS_ROWIDS;
  --invoke REFRESH_MATERIALIZED_VIEW@MY_DB when a change is detected in the table (see query below)
  l_regds := SYS.CHNF$_REG_INFO ('MY_SCHEMA.REFRESH_MATERIALIZED_VIEW@MY_DB', l_qosflags, 0,0,0);
  l_regid := DBMS_CHANGE_NOTIFICATION.new_reg_start (l_regds);
  --upon changes on the results returned from this query, a notification will be triggered
  SELECT count(*)
  INTO   v_n
  FROM   monitored_table;
  DBMS_CHANGE_NOTIFICATION.reg_end;
END;
/

添加触发通知的记录:

--trigger a Query Change
insert into monitored_table values(2, systimestamp);
insert into monitored_table values(3, systimestamp);

--note that the notification is triggered once for each commit
commit;

最后检查您的视图是否已刷新

select * from mat_view;

无论如何,无论您做什么,都要注意在性能方面付出的代价。如果您正在监视包含日志的 table,它很可能是一个高 volume/frequency 数据,因此您可能不希望频繁或每次提交同步您的视图。