在 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:
- 使用 DBMS_SCHEDULER.CREATE_PROGRAM 创建命名程序。
- 使用DBMS_SCHEDULER.CREATE_CHAIN创建链。
- 使用 DBMS_SCHEDULER.DEFINE_CHAIN_STEP 定义链中的步骤以调用在 #1 中创建的命名程序。
- 使用DBMS_SCHEDULER.DEFINE_CHAIN_RULE来定义何时调用步骤(这是定义同步和异步调用的地方)。
- 使用 DBMS_SCHEDULER.CREATE_SCHEDULE 创建一个计划以确定 #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;
/
沿途的有用链接:
- http://docs.oracle.com/cd/B28359_01/server.111/b28310/schedadmin006.htm#BAJHFHCD
- http://docs.oracle.com/cd/B28359_01/appdev.111/b28419/d_sched.htm#i1011194
- http://docs.oracle.com/cd/B19306_01/server.102/b14231/scheduse.htm#CHDGAJAG
- https://docs.oracle.com/cd/B28359_01/server.111/b28310/scheduse009.htm#CHDCFBHG
- http://dba.fyicenter.com/faq/oracle/PL-SQL-Named-Program-Unit.html
我有 7 个实体化视图需要按计划刷新。
其中五个独立于数据源,可以异步重建。
其中两个依赖于前五个 MView 中的一些,需要等到它们被刷新。最后两个相互独立,可以 运行 异步。
我最初问过这个问题
我的问题改为:在 Oracle 11g 中执行同步和异步 MView 刷新的更好方法是什么?
我想分享我使用的 DBMS_SCHEDULER 解决方案,以防有人对在 Oracle 11g 中处理同步和异步方法调用的更好方法感兴趣。
TLDR:
- 使用 DBMS_SCHEDULER.CREATE_PROGRAM 创建命名程序。
- 使用DBMS_SCHEDULER.CREATE_CHAIN创建链。
- 使用 DBMS_SCHEDULER.DEFINE_CHAIN_STEP 定义链中的步骤以调用在 #1 中创建的命名程序。
- 使用DBMS_SCHEDULER.DEFINE_CHAIN_RULE来定义何时调用步骤(这是定义同步和异步调用的地方)。
- 使用 DBMS_SCHEDULER.CREATE_SCHEDULE 创建一个计划以确定 #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;
/
沿途的有用链接:
- http://docs.oracle.com/cd/B28359_01/server.111/b28310/schedadmin006.htm#BAJHFHCD
- http://docs.oracle.com/cd/B28359_01/appdev.111/b28419/d_sched.htm#i1011194
- http://docs.oracle.com/cd/B19306_01/server.102/b14231/scheduse.htm#CHDGAJAG
- https://docs.oracle.com/cd/B28359_01/server.111/b28310/scheduse009.htm#CHDCFBHG
- http://dba.fyicenter.com/faq/oracle/PL-SQL-Named-Program-Unit.html