在 Oracle 11g 中进行同步和异步 MView 刷新的更好方法是什么?

What is a better way to do synchronous and asynchronous MView refreshes in Oracle 11g?

我有 7 个实体化视图需要按计划刷新。

其中五个独立于数据源,可以异步重建。

其中两个依赖于前五个 MView 中的一些,需要等到它们被刷新。最后两个相互独立,可以 运行 异步。

我最初问过这个问题。我的计划是走 DBMS_JOB.SUBMIT 路线。有人向我解释说 DBMS_JOB.SUBMIT 是解决该问题的 Oracle 8 级方法,我应该考虑使用 DBMS_SCHEDULER.

我的问题改为:在 Oracle 11g 中执行同步和异步 MView 刷新的更好方法是什么?

我想分享我使用的 DBMS_SCHEDULER 解决方案,以防有人对在 Oracle 11g 中处理同步和异步方法调用的更好方法感兴趣。

TLDR:

  1. 使用 DBMS_SCHEDULER.CREATE_PROGRAM 创建命名程序。
  2. 使用DBMS_SCHEDULER.CREATE_CHAIN创建链。
  3. 使用 DBMS_SCHEDULER.DEFINE_CHAIN_STEP 定义链中的步骤以调用在 #1 中创建的命名程序。
  4. 使用DBMS_SCHEDULER.DEFINE_CHAIN_RULE来定义何时调用步骤(这是定义同步和异步调用的地方)。
  5. 使用 DBMS_SCHEDULER.CREATE_SCHEDULE 创建一个计划以确定 #6 中创建的作业何时会 运行。
  6. 使用DBMS_SCHEDULER.CREATE_JOB创建一个作业,该作业将运行根据在#5 中创建的计划来执行在#2 中创建的链。

代码:

-- First: Create the programs to refresh the MViews
BEGIN
  -- Independent Programs
  DBMS_SCHEDULER.CREATE_PROGRAM (
      program_name => 'PROGRAM_REFRESH_MVIEW_I1', 
      program_action => 'BEGIN DBMS_MVIEW.REFRESH(list => ''IndependentMView1'', METHOD => ''C'') ; END;', 
      program_type => 'PLSQL_BLOCK', 
      number_of_arguments => 0, 
      comments => 'This Refreshes the IndependentMView1 MView.', 
      enabled => TRUE) ;
  DBMS_SCHEDULER.CREATE_PROGRAM (
      program_name => 'PROGRAM_REFRESH_MVIEW_I2', 
      program_action => 'BEGIN DBMS_MVIEW.REFRESH(list => ''IndependentMView2'', METHOD => ''C'') ; END;', 
      program_type => 'PLSQL_BLOCK', 
      number_of_arguments => 0, 
      comments => 'This Refreshes the IndependentMView2 MView.', 
      enabled => TRUE) ;
  DBMS_SCHEDULER.CREATE_PROGRAM (
      program_name => 'PROGRAM_REFRESH_MVIEW_I3', 
      program_action => 'BEGIN DBMS_MVIEW.REFRESH(list => ''IndependentMView3'', METHOD => ''C'') ; END;', 
      program_type => 'PLSQL_BLOCK', 
      number_of_arguments => 0, 
      comments => 'This Refreshes the IndependentMView3 MView.', 
      enabled => TRUE) ;
  DBMS_SCHEDULER.CREATE_PROGRAM (
      program_name => 'PROGRAM_REFRESH_MVIEW_I4', 
      program_action => 'BEGIN DBMS_MVIEW.REFRESH(list => ''IndependentMView4'', METHOD => ''C'') ; END;', 
      program_type => 'PLSQL_BLOCK', 
      number_of_arguments => 0, 
      comments => 'This Refreshes the IndependentMView4 MView.', 
      enabled => TRUE) ;
  DBMS_SCHEDULER.CREATE_PROGRAM (
      program_name => 'PROGRAM_REFRESH_MVIEW_I5', 
      program_action => 'BEGIN DBMS_MVIEW.REFRESH(list => ''IndependentMView5'', METHOD => ''C'') ; END;', 
      program_type => 'PLSQL_BLOCK', 
      number_of_arguments => 0, 
      comments => 'This Refreshes the IndependentMView5 MView.', 
      enabled => TRUE) ;

  -- Dependent Programs
  DBMS_SCHEDULER.CREATE_PROGRAM (
      program_name => 'PROGRAM_REFRESH_MVIEW_D1', 
      program_action => 'BEGIN DBMS_MVIEW.REFRESH(list => ''DependentMView1'', METHOD => ''C'') ; END;', 
      program_type => 'PLSQL_BLOCK', 
      number_of_arguments => 0, 
      comments => 'This Refreshes the DependentMView1 MView.', 
      enabled => TRUE) ;
  DBMS_SCHEDULER.CREATE_PROGRAM (
      program_name => 'PROGRAM_REFRESH_MVIEW_D2', 
      program_action => 'BEGIN DBMS_MVIEW.REFRESH(list => ''DependentMView2'', METHOD => ''C'') ; END;', 
      program_type => 'PLSQL_BLOCK', 
      number_of_arguments => 0, 
      comments => 'This Refreshes the DependentMView2 MView.', 
      enabled => TRUE) ;
END;

/

-- Next: Create the chain to control the refresh steps
BEGIN
  DBMS_SCHEDULER.CREATE_CHAIN (
  chain_name => 'REFRESH_MVIEWS_CHAIN', 
  rule_set_name => NULL, 
  evaluation_interval => NULL, 
  comments => 'Refresh the Materialized Views in the correct order.') ;
END;

/

  -- Next: Create the steps used to call the programs to refresh the MViews. 
  -- Note: Referenced programs must be enabled.
BEGIN
  DBMS_SCHEDULER.DEFINE_CHAIN_STEP ('REFRESH_MVIEWS_CHAIN', 'stepI1', 'PROGRAM_REFRESH_MVIEW_I1') ;
  DBMS_SCHEDULER.DEFINE_CHAIN_STEP ('REFRESH_MVIEWS_CHAIN', 'stepI2', 'PROGRAM_REFRESH_MVIEW_I2') ;
  DBMS_SCHEDULER.DEFINE_CHAIN_STEP ('REFRESH_MVIEWS_CHAIN', 'stepI3', 'PROGRAM_REFRESH_MVIEW_I3') ;
  DBMS_SCHEDULER.DEFINE_CHAIN_STEP ('REFRESH_MVIEWS_CHAIN', 'stepI4', 'PROGRAM_REFRESH_MVIEW_I4') ;
  DBMS_SCHEDULER.DEFINE_CHAIN_STEP ('REFRESH_MVIEWS_CHAIN', 'stepI5', 'PROGRAM_REFRESH_MVIEW_I5') ;

  -- stepD1 is dependent on IndependentMView1, IndependentMView2, IndependentMView3
  DBMS_SCHEDULER.DEFINE_CHAIN_STEP ('REFRESH_MVIEWS_CHAIN', 'stepD1', 'PROGRAM_REFRESH_MVIEW_D1') ;
  -- stepD2 is dependent on IndependentMView1, IndependentMView4
  DBMS_SCHEDULER.DEFINE_CHAIN_STEP ('REFRESH_MVIEWS_CHAIN', 'stepD2', 'PROGRAM_REFRESH_MVIEW_D2') ;
END;

/

-- Next: Define rules for the chain.  This is where we establish the 
-- synchronous and asynchronous order of things. (i.e. where the magic happens)
BEGIN
  -- First, start all independent steps asynchronously
  DBMS_SCHEDULER.DEFINE_CHAIN_RULE ('REFRESH_MVIEWS_CHAIN', 'TRUE', 'START stepI1, stepI2, stepI3, stepI4, stepI5') ;
  -- Next, start dependent steps as their related independent steps complete.
  DBMS_SCHEDULER.DEFINE_CHAIN_RULE ('REFRESH_MVIEWS_CHAIN', 'stepI1 COMPLETED AND stepI2 COMPLETED AND stepI3 COMPLETED', 'START stepD1') ;
  DBMS_SCHEDULER.DEFINE_CHAIN_RULE ('REFRESH_MVIEWS_CHAIN', 'stepI1 COMPLETED AND stepI4 COMPLETED', 'Start stepD2') ;
  -- Last, define when the chain is complete.
  -- In this case, we're done when both dependent steps and the one independent step that no other steps are dependent upon are all complete.
  DBMS_SCHEDULER.DEFINE_CHAIN_RULE ('REFRESH_MVIEWS_CHAIN', 'stepI5 COMPLETED AND stepD1 COMPLETED AND stepD2 COMPLETED', 'END') ;

  -- Enable the chain
  DBMS_SCHEDULER.ENABLE ('REFRESH_MVIEWS_CHAIN') ;
END;

/

-- Next: create a schedule to run every 30 minutes at the top and bottom of every hour
BEGIN
  DBMS_SCHEDULER.CREATE_SCHEDULE ( 
      schedule_name => 'THIRTY_MINUTE_SCHEDULE', 
      repeat_interval => 'FREQ=MINUTELY;INTERVAL=30', 
      start_date => TO_TIMESTAMP_TZ ('2015-11-2 0:0:00.000000000 UTC', 'YYYY-MM-DD HH24:MI:SS.FF TZR'), 
      comments => 'Fires at the top and bottom of every hour') ;
END;

/

-- Lastly: Create a job to start the REFRESH_MVIEWS_CHAIN chain based on the THIRTY_MINUTE_SCHEDULE created above.
BEGIN
  DBMS_SCHEDULER.CREATE_JOB (
      job_name => 'REFRESH_MVIEWS_JOB', 
      job_type => 'CHAIN', 
      job_action => 'REFRESH_MVIEWS_CHAIN', 
      schedule_name => 'TEN_TILL_TOP_BOTTOM_SCHEDULE', 
      number_of_arguments => 0, 
      enabled => FALSE, 
      auto_drop => FALSE, 
      comments => 'Refresh the Materialized Views');

  DBMS_SCHEDULER.SET_ATTRIBUTE (
      name => 'REFRESH_MVIEWS_JOB', 
      attribute => 'logging_level', 
      value => DBMS_SCHEDULER.LOGGING_OFF) ;

  -- Enable the refresh job
  DBMS_SCHEDULER.ENABLE (name => 'REFRESH_MVIEWS_JOB') ;
END;

/

沿途的有用链接: