问题
I have 7 Materialized Views that need to be refreshed on a schedule.
Five of them are data source independent and could be rebuilt asynchronously.
Two of them are dependent on some of the first five MViews and need to wait until those have been refreshed. These last two are independent of each other and could run asynchronously.
I originally asked this question here. My plan was to go the DBMS_JOB.SUBMIT route. It was explained to me that DBMS_JOB.SUBMIT is an Oracle 8-level approach to the problem and that I should look into using DBMS_SCHEDULER.
My question changed to: What is a better way to do synchronous and asynchronous MView refreshes in Oracle 11g?
I'd like to share the DBMS_SCHEDULER solution I used in case anyone is interested in a better approach to working with synchronous and asynchronous method calls in Oracle 11g.
回答1:
TLDR:
- Use DBMS_SCHEDULER.CREATE_PROGRAM to create named programs.
- Use DBMS_SCHEDULER.CREATE_CHAIN to create a chain.
- Use DBMS_SCHEDULER.DEFINE_CHAIN_STEP to define the steps in the chain to call the named programs created in #1.
- Use DBMS_SCHEDULER.DEFINE_CHAIN_RULE to define when steps are called (this is where the synchronous and asynchronous calls are defined).
- Use DBMS_SCHEDULER.CREATE_SCHEDULE to create a schedule to determine when the job created in #6 will run.
- Use DBMS_SCHEDULER.CREATE_JOB to create a job that will run based on the schedule created in #5 to execute the chain created in #2.
Code:
-- 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;
/
Useful links along the way:
- https://stackoverflow.com/a/16416525/384884
- 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
来源:https://stackoverflow.com/questions/33505310/what-is-a-better-way-to-do-synchronous-and-asynchronous-mview-refreshes-in-oracl