【问题标题】:How to call multiple procedures in parallel in Oracle 12c?Oracle 12c 中如何并行调用多个过程?
【发布时间】:2018-11-28 03:16:12
【问题描述】:

我有一个程序如下,

CREATE OR REPLACE PROCEDURE engineering_all ( idx IN NUMBER )
IS
tempstmt VARCHAR2(2000);
BEGIN
create_table_like( 'results_temp', 'results', 1);

tempstmt :=  'ALTER TABLE results_temp CACHE';
EXECUTE IMMEDIATE tempstmt;

engineering('CONSERVATIVE', idx);
engineering('INTERMEDIATE', idx);
engineering('AGGRESSIVE',   idx);
END;
/

对过程工程的三个调用是相互独立的,所以我想并行化它。我遇到了多种方式,例如 DBMS_PARALLEL_EXECUTE、DBMS_JOB、DBMS_SCHEDULER,但无法确定哪种方式对我的时间优化目标最有效。

请帮我弄清楚该选择哪一个,我该如何实施?

【问题讨论】:

    标签: oracle plsql multiprocessing dbms-scheduler dbms-job


    【解决方案1】:

    我建议使用DBMS_PARALLEL_EXECUTE。主会话等待子并行会话完成。有统计和结果的方便视图 - user_parallel_execute_chunksuser_parallel_execute_tasks。我们在项目中使用它,觉得很方便。

    有一点是这个包需要分块,只能通过 rowid 或数字来完成。所以首先你必须创建一个接受数字的过程。这是适合您的情况:

    create or replace procedure engineering_parallel(
      iLaunchType number, 
      idx         number
    ) 
    is
    begin
      if iLaunchType = 1 then
        engineering('CONSERVATIVE',idx);
      elsif iLaunchType = 2 then
        engineering('INTERMEDIATE',idx);
      elsif iLaunchType = 3 then
        engineering('AGGRESSIVE',idx);
      end if;
    end;
    

    在这里你会找到一个在匿名 pl/sql 块中启动你的案例的例子,你可以很容易地将它转换成engineering_all 过程:

    declare
      -- idx parameter
      idx number := 0;
      -- unique parallel task name
      sTaskName varchar2(32767) := 'ENGINEERING-'||to_char(sysdate,'yyyy-mm-dd-hh24-mi-ss');
      -- this is where you store the query to split into chunks
      sChunkSQL varchar2(32767) := 'select level start_id, '||idx||' end_id'||chr(10)||
                                   'from   dual connect by level <= 3';
      -- this is the procedure call
      sParallelSQL varchar2(32767) := 'begin engineering_parallel(:start_id,:end_id); end;';
      -- parallel degree
      iParalleDegree number := 3;
    begin
      -- create a task
      DBMS_PARALLEL_EXECUTE.create_task(task_name => sTaskName);
    
      -- chunking
      DBMS_PARALLEL_EXECUTE.create_chunks_by_sql(
        task_name => sTaskName,
        sql_stmt  => sChunkSQL,
        by_rowid  => FALSE
      );
    
      -- launch. current session waits till all child parallel sessions are finished
      DBMS_PARALLEL_EXECUTE.run_task(
        task_name      => sTaskName,
        sql_stmt       => sParallelSQL,
        language_flag  => DBMS_SQL.NATIVE,
        parallel_level => iParalleDegree
      );
    
      dbms_output.put_line(
        'Job is finished.'||
        'Check user_parallel_execute_chunks, user_parallel_execute_tasks for the task '||
        sTaskName
      );
    
    end;  
    

    最后一点要考虑 - 检查您的版本是否包含 Bug 18966843 的修复: 升级到 11.2.0.4 后的 DBMS_PARALLEL_EXECUTE 性能延迟 我们在 12.1 中遇到过它,但有补丁可以修复它。 如果它不固定,那么你有可能最后的平行度将低于要求(下降到 1)。

    【讨论】:

      【解决方案2】:

      我从未使用过您提到的第一个选项,但是 - 在 DBMS_JOBDBMS_SCHEDULERDBMS_JOB 之间进行选择更简单,所以我会选择它。以最简单的方式,过程可能如下所示:

      CREATE OR REPLACE PROCEDURE engineering_all (idx IN NUMBER)
      IS
         l_job      NUMBER;
         tempstmt   VARCHAR2 (2000);
      BEGIN
         create_table_like ('results_temp', 'results', 1);
         tempstmt := 'ALTER TABLE results_temp CACHE';
      
         EXECUTE IMMEDIATE tempstmt;
      
         DBMS_JOB.submit (
            job         => l_job,
            what        => 'begin engineering(''CONSERVATIVE'', ' || idx || '); end;',
            next_date   => SYSDATE,
            interval    => NULL);
      
         DBMS_JOB.submit (
            job         => l_job,
            what        => 'begin engineering(''INTERMEDIATE'', ' || idx || '); end;',
            next_date   => SYSDATE,
            interval    => NULL);
      
         DBMS_JOB.submit (
            job         => l_job,
            what        => 'begin engineering(''AGGRESSIVE'', ' || idx || '); end;',
            next_date   => SYSDATE,
            interval    => NULL);
      
         COMMIT;
      END;
      /
      

      【讨论】:

      • DBMS_JOB 在 12.2 中为 deprecated
      • 哦。谢谢你,@wolφi。让我们希望 OP 提到的“12c”是 R1,然后:) 或者这个选项不起作用,这根本不是那么糟糕 - 他不必在 3 个选项中进行选择,而是在 2 个选项之间进行选择。然后有 50% 的机会选择一个,但你有 90% 的机会选择错误一个(墨菲说)。
      • 感谢您的回答,但不幸的是,此 dbms_job.submit 并未调用程序工程。这个过程应该创建一个新表,在调用之后我看不到它,尽管对 engineering_all 过程的调用是成功的,没有任何错误迹象。
      • 我正在使用 oracle 12c R1
      • 我在发布之前对其进行了测试,所以 - 是的,它正在调用该过程。由于通过 DBMS_JOB 执行,您不会立即看到结果。稍后再检查(,而不是小时)。
      猜你喜欢
      • 2013-08-14
      • 1970-01-01
      • 1970-01-01
      • 2021-05-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-26
      • 2021-06-03
      相关资源
      最近更新 更多