您可以刷新触发器内的物化视图吗?甲骨文 11g

Posted

技术标签:

【中文标题】您可以刷新触发器内的物化视图吗?甲骨文 11g【英文标题】:Can you refresh materialised view inside a trigger? Oracle 11g 【发布时间】:2021-12-01 00:35:08 【问题描述】:

基本上我有一个物化视图,当特定表 HISTORY_TABLE 更新时需要每月刷新一次,即 HISTORY_TABLE 仅插入到 c 中。每月一次。物化视图不包含与 HISTORY_TABLE 相关的数据,因此我无法在提交时刷新(据我所知)。

根据我一直在阅读的内容,由于刷新时的隐式提交,因此无法刷新触发器内的 Mview。关于如何解决这个问题的任何想法?

DROP TRIGGER SYSADM.COMPLETE_NOTIF_SMS;

CREATE OR REPLACE TRIGGER SYSADM.COMPLETE_NOTIF_SMS
AFTER INSERT
ON SYSADM.HISTORY_TABLE
REFERENCING NEW AS New OLD AS Old
FOR EACH ROW
DECLARE

   V_STATUS   NUMBER;
   V_NOTIFICATION_TEXT VARCHAR2(100);
   V_CHECK_CATEGORY VARCHAR2(100);
   
BEGIN
      
      insert into some_table values (v_check_category, v_notification_text,sysdate);  
      -- I want to refresh the Mview/snapshot here 
      DBMS_SNAPSHOT.REFRESH('mview_to_refresh');
                   
EXCEPTION
   WHEN OTHERS
   THEN
      
      -- Some variables are set to send an email.  
   
      RAISE;
END NOTIF_SMS;
/

【问题讨论】:

如果您的 MV 不包含与 History_table 更新相关的数据,那么您不应将刷新基于更新该表。设置刷新作业(dbms_job 或 dbms_scheduler)或您的外部调度程序。仅仅因为您希望它们在同一时间运行并不意味着它们应该是同一过程的一部分。顺便说一句,如果您在历史记录表中插入 10K 行,您将刷新 MV 10K 次。 【参考方案1】:

我不确定我是否做对了,但我使用这样的全局参数刷新了我的视图:

    我创建了一个这样的包来设置我想要使用的值:

create or replace package dwh.DWH_GLOBAL_PARAMS_MANAGER is

  -- Author  : ALI.FIDANLI
  -- Created : 21.03.2019 10:33:25
  -- Purpose : kelepelik


      PROCEDURE SET_ACC_DATE_CTX(PDATE DATE);


end DWH_GLOBAL_PARAMS_MANAGER;    

CREATE OR REPLACE PACKAGE BODY DWH.DWH_GLOBAL_PARAMS_MANAGER IS
      -- Author  : ALI.FIDANLI
      -- Created : 21.03.2019 10:33:25
      -- Purpose : kelepelik
            PROCEDURE SET_ACC_DATE_CTX(PDATE DATE)
          AS
        BEGIN
            dbms_session.set_context('DWH_PARAMS','REPORT_DATE',TO_CHAR(PDATE,'dd.mm.yyyy'));
            dbms_session.set_context('DWH_PARAMS','REPORT_DATE-1',TO_CHAR(PDATE-1,'dd.mm.yyyy'));
          END;
    END DWH_GLOBAL_PARAMS_MANAGER;

    我在视图中使用了这些参数以及所需的参数:

  -- Author  : ALI.FIDANLI
  -- Created : 21.03.2019 10:33:25
  -- Purpose : kelepelik
CREATE OR REPLACE VIEW DWH.V_F_ACCOUNT AS
SELECT TO_DATE (SYS_CONTEXT ('DWH_PARAMS', 'REPORT_DATE-1'),'dd.mm.yyyy')  REPORT_DATE,
                 C.ACC_NO,
                 C.ACC_CURRENCY,
 pkg.func(C.ACC_NO, TO_DATE (SYS_CONTEXT ('DWH_PARAMS', 'REPORT_DATE-1'),'dd.mm.yyyy') ,C.ACC_GL_CODE) ACC_GL_CODE,        
            FROM xxxx.tablename C) ACC

所以我设置日期使用

begin
  -- Call the procedure
  dwh.dwh_global_params_manager.set_acc_date_ctx(pdate => :pdate);
end;

并使用我的观点....

让我知道它是否适合你,如果不适合我将删除我的回复

【讨论】:

【参考方案2】:

对;您无法直接从触发器刷新物化视图,因为您无法在触发器内提交。实际上,您可以,但是触发器必须是一个自治事务,但是 - 不幸的是 - 不起作用,因为它是另一个会话,所以它看不到新添加到表中的行触发器触发。

解决方法可能是

必须提交的存储过程(自治事务) 为什么?因为它将安排一个刷新物化视图的作业,并且dbms_job.submit 需要提交。当它传播回调用者(即触发器)并且 - 请记住 - 您不能在触发器内提交,因此过程必须是一个自治事务。 作业将在初始插入后几分钟运行,假设您将在此之前提交主事务。

这是一个例子。

您的some_table,原始表格内容和物化视图:

SQL> create table some_table (cat varchar2(10), text varchar2(10), datum date);

Table created.

SQL> create materialized view mv_dept as select * from dept;

Materialized view created.

SQL> select * from dept;

    DEPTNO DNAME          LOC
---------- -------------- -------------
        10 ACCOUNTING     NEW YORK
        20 RESEARCH       DALLAS
        30 SALES          CHICAGO
        40 OPERATIONS     BOSTON

SQL> select * from mv_dept;

    DEPTNO DNAME          LOC
---------- -------------- -------------
        10 ACCOUNTING     NEW YORK
        20 RESEARCH       DALLAS
        30 SALES          CHICAGO
        40 OPERATIONS     BOSTON

SQL>

过程(自主事务,安排刷新物化视图的作业):

SQL> create or replace procedure p_submit as
  2    pragma autonomous_transaction;
  3    i      number;
  4  begin
  5    dbms_job.submit(i,
  6                    'begin DBMS_SNAPSHOT.REFRESH(''mv_dept''); end;',
  7                    sysdate + 1/(24*60),
  8                    'null'
  9                   );
 10    commit;
 11  end;
 12  /

Procedure created.

触发器(调用过程):

SQL> create or replace trigger complete_notif_sms
  2    after insert on dept
  3    for each row
  4  declare
  5    v_status            number;
  6    v_notification_text varchar2(100);
  7    v_check_category    varchar2(100);
  8  begin
  9    insert into some_table values (v_check_category, v_notification_text,sysdate);
 10
 11    -- I want to refresh the Mview/snapshot here
 12    p_submit;
 13  end notif_sms;
 14  /

Trigger created.

SQL>

只是设置日期格式;你不必这样做:

SQL> alter session set nls_date_format = 'dd.mm.yyyy hh24:mi:ss';

Session altered.

让我们尝试一下:在作为物化视图源的表中插入一行:

SQL> insert into dept (deptno, dname, loc) values (1, 'a', 'b');

1 row created.

新添加的行在表中...

SQL> select * from dept;

    DEPTNO DNAME          LOC
---------- -------------- -------------
        10 ACCOUNTING     NEW YORK
        20 RESEARCH       DALLAS
        30 SALES          CHICAGO
        40 OPERATIONS     BOSTON
         1 a              b

...但不在物化视图中,因为作业尚未开始:

SQL> select * from mv_dept;

    DEPTNO DNAME          LOC
---------- -------------- -------------
        10 ACCOUNTING     NEW YORK
        20 RESEARCH       DALLAS
        30 SALES          CHICAGO
        40 OPERATIONS     BOSTON

工作信息:

SQL> select job, last_date, next_date from user_jobs;

       JOB LAST_DATE           NEXT_DATE
---------- ------------------- -------------------
         8                     12.10.2021 20:34:11

SQL> commit;

Commit complete.

SQL>

一分钟后:

SQL> select sysdate from dual;

SYSDATE
-------------------
12.10.2021 20:36:08

工作已经完成;因为这是一次性工作,所以它从 user_jobs 消失了:

SQL> select job, last_date, next_date from user_jobs;

no rows selected

我们希望物化视图中也有一个新行:

SQL> select * from mv_dept;

    DEPTNO DNAME          LOC
---------- -------------- -------------
        10 ACCOUNTING     NEW YORK
        20 RESEARCH       DALLAS
        30 SALES          CHICAGO
        40 OPERATIONS     BOSTON
         1 a              b

SQL>

没错,就在这里。

【讨论】:

以上是关于您可以刷新触发器内的物化视图吗?甲骨文 11g的主要内容,如果未能解决你的问题,请参考以下文章

测试mv刷新组是否可以同时刷新组内物化视图

触发物化视图刷新 - AWS Lambda

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

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

PostgreSQL定时刷新物化视图的一种简单方法

如何做到物化视图的自动刷新