oracle-databasestored-proceduresplsqlparallel-processingdbms-scheduler

Run procedures in parallel - Oracle PL/SQL


I am trying to run stored procedures in parallel - Oracle PL/SQL using dbms_scheduler but I am getting an error like an unknown job, I have also tried dbms_job, here I am getting an error- identifier dbms_jobs must be declared. Could someone please help me out? Below are two approaches I have tried:

CREATE PACKAGE BODY pkg IS
CREATE PROCEDURE do_parallel_execution
IS
BEGIN
   DBMS_SCHEDULER.RUN_JOB('pkg1.proc1', false);
   DBMS_SCHEDULER.RUN_JOB('pkg1.proc2', false);
   DBMS_SCHEDULER.RUN_JOB('pkg1.proc3', false);
END;

CREATE PACKAGE BODY pkg IS
CREATE PROCEDURE run_in_parallel
IS
   l_jobno pls_integer;
BEGIN
   dbms_job.submit(l_jobno, 'pkg1.proc1; end;' );
   dbms_job.submit(l_jobno, 'pkg1.proc2; end;' );
  -- dbms_job.submit(l_jobno, 'pkg1.proc3; end;' );
END;

where pkg1 has all 3 procedures defined in it. Thank you!


Solution

  • To execute otherwise unrelated procedures in parallel, use a Scheduler Job Chain:

    Create procedures:

    create or replace package test as
        procedure test1;
        procedure test2;
        procedure test3;
    end test;
    /
    
    create or replace package body test as
        procedure test1 is
        begin
            sys.dbms_session.sleep(5);
        end test1;
    
        procedure test2 is
        begin
            sys.dbms_session.sleep(5);
        end test2;
    
        procedure test3 is
        begin
            sys.dbms_session.sleep(5);
        end test3;
    end test;
    /
    

    Create Scheduler Programs for each procedure:

    BEGIN
        DBMS_SCHEDULER.create_program(
            program_name => 'TEST1_PROGRAM',
            program_action => 'TEST.TEST1',
            program_type => 'STORED_PROCEDURE',
            number_of_arguments => 0,
            comments => NULL,
            enabled => FALSE);
    
        DBMS_SCHEDULER.ENABLE(name=>'TEST1_PROGRAM');    
    
        DBMS_SCHEDULER.create_program(
            program_name => 'TEST2_PROGRAM',
            program_action => 'TEST.TEST2',
            program_type => 'STORED_PROCEDURE',
            number_of_arguments => 0,
            comments => NULL,
            enabled => FALSE);
    
        DBMS_SCHEDULER.ENABLE(name=>'TEST2_PROGRAM');    
    
        DBMS_SCHEDULER.create_program(
            program_name => 'TEST3_PROGRAM',
            program_action => 'TEST.TEST3',
            program_type => 'STORED_PROCEDURE',
            number_of_arguments => 0,
            comments => NULL,
            enabled => FALSE);
    
        DBMS_SCHEDULER.ENABLE(name=>'TEST3_PROGRAM');    
    END;
    /
    

    Create the Scheduler Chain:

    BEGIN
      -- one step for each program
      SYS.DBMS_SCHEDULER.DEFINE_CHAIN_STEP (
         chain_name          => 'TEST_CHAIN'
        ,step_name           => 'CHAIN_STEP1'
        ,program_name        => 'TEST1_PROGRAM');
    
      SYS.DBMS_SCHEDULER.DEFINE_CHAIN_STEP (
         chain_name          => 'TEST_CHAIN'
        ,step_name           => 'CHAIN_STEP2'
        ,program_name        => 'TEST2_PROGRAM');
    
      SYS.DBMS_SCHEDULER.DEFINE_CHAIN_STEP (
         chain_name          => 'TEST_CHAIN'
        ,step_name           => 'CHAIN_STEP3'
        ,program_name        => 'TEST3_PROGRAM');
    
      -- one rule with condition "true" to start each step immediately
      SYS.DBMS_SCHEDULER.DEFINE_CHAIN_RULE  (
          CHAIN_NAME  => 'TEST_CHAIN',
          rule_name  => 'TEST_RULE1',
          condition => 'TRUE',
          action => 'START "CHAIN_STEP1"');   
    
      SYS.DBMS_SCHEDULER.DEFINE_CHAIN_RULE  (
          CHAIN_NAME  => 'TEST_CHAIN',
          rule_name  => 'TEST_RULE2',
          condition => 'TRUE',
          action => 'START "CHAIN_STEP2"');   
    
      SYS.DBMS_SCHEDULER.DEFINE_CHAIN_RULE  (
          CHAIN_NAME  => 'TEST_CHAIN',
          rule_name  => 'TEST_RULE3',
          condition => 'TRUE',
          action => 'START "CHAIN_STEP3"');   
    
      -- one rule to close out the chain after all steps are completed    
      SYS.DBMS_SCHEDULER.DEFINE_CHAIN_RULE (
         chain_name          => 'TEST_CHAIN',
         rule_name           => 'TEST_RULE4',
         condition           => 'CHAIN_STEP1 Completed AND CHAIN_STEP2 Completed AND CHAIN_STEP3 Completed',
         action              => 'END 0');
    
    END;
    /
    

    The chain flow now looks like this (as depicted by SQL Developer):

    enter image description here

    Now create a Scheduler Job to run the chain:

    BEGIN
        DBMS_SCHEDULER.CREATE_JOB (
                job_name => 'TEST_JOB',
                job_type => 'CHAIN',
                job_action => 'TEST_CHAIN',
                number_of_arguments => 0,
                start_date => NULL,
                repeat_interval => NULL,
                end_date => NULL,
                enabled => FALSE,
                auto_drop => FALSE,
                comments => '');
    
        DBMS_SCHEDULER.SET_ATTRIBUTE( 
                 name => 'TEST_JOB', 
                 attribute => 'logging_level', value => DBMS_SCHEDULER.LOGGING_RUNS);
    
    END;
    /
    

    And run the job:

    BEGIN
        DBMS_SCHEDULER.RUN_JOB(job_name => 'TEST_JOB', USE_CURRENT_SESSION => FALSE);
    END;
    /
    

    Now look at the job run details for the job:

    "LOG_ID" "LOG_DATE"                               "JOB_NAME" "JOB_SUBNAME" "STATUS"    "ERROR#" "ACTUAL_START_DATE"                                "RUN_DURATION"
    "1548"   "14-JUN-20 12.15.46.744612000 AM -04:00" "TEST_JOB" "CHAIN_STEP3" "SUCCEEDED" "0"      "14-JUN-20 12.15.41.708043000 AM AMERICA/NEW_YORK" "+00 00:00:05.000000"
    "1544"   "14-JUN-20 12.15.46.746544000 AM -04:00" "TEST_JOB" "CHAIN_STEP2" "SUCCEEDED" "0"      "14-JUN-20 12.15.41.690404000 AM AMERICA/NEW_YORK" "+00 00:00:05.000000"
    "1546"   "14-JUN-20 12.15.46.748830000 AM -04:00" "TEST_JOB" "CHAIN_STEP1" "SUCCEEDED" "0"      "14-JUN-20 12.15.41.690891000 AM AMERICA/NEW_YORK" "+00 00:00:05.000000"
    "1550"   "14-JUN-20 12.15.46.968592000 AM -04:00" "TEST_JOB" ""            "SUCCEEDED" "0"      "14-JUN-20 12.15.41.574115000 AM AMERICA/NEW_YORK" "+00 00:00:05.000000"
    

    Note that: