在 PL/SQL 中并行化调用

Posted

技术标签:

【中文标题】在 PL/SQL 中并行化调用【英文标题】:Parallelizing calls in PL/SQL 【发布时间】:2013-01-25 21:47:52 【问题描述】:

我有一个带有 proc 的包,它将执行许多其他过程,如下所示:

CREATE PACKAGE BODY pkg IS
    CREATE PROCEDURE do
    IS
    BEGIN
        other_pkg.other_proc;
        other_pkg2.other_proc2;
        other_pkg3.other_proc3;
    END;
END;

有没有办法让程序并行执行而不是串行执行?

编辑:

这是在这种情况下使用DBMS_SCHEDULER 的正确方法吗:

CREATE PACKAGE BODY pkg IS
    CREATE PROCEDURE do
    IS
    BEGIN
        DBMS_SCHEDULER.CREATE_JOB('job_other_pkg.other_proc', 'STORED_PROCEDURE', 'other_pkg.other_proc;');
        DBMS_SCHEDULER.RUN_JOB('job_other_pkg.other_proc', FALSE);
        -- ...
    END;
END;

【问题讨论】:

【参考方案1】:

您可以使用dbms_job(或dbms_scheduler)包来提交将并行运行的作业。如果您使用dbms_job,提交作业将成为事务的一部分,因此作业将在事务完成后开始。

CREATE PACKAGE BODY pkg IS
    CREATE PROCEDURE do
    IS
      l_jobno pls_integer;
    BEGIN
        dbms_job.submit(l_jobno, 'begin other_pkg.other_proc; end;' );
        dbms_job.submit(l_jobno, 'begin other_pkg2.other_proc2; end;' );
        dbms_job.submit(l_jobno, 'begin other_pkg3.other_proc3; end;' );
    END;
END;

如果您使用dbms_scheduler,则创建新作业不是事务性的(即每次创建新作业时都会有隐式提交),如果事务中有其他工作正在完成,这可能会导致事务完整性问题调用此过程的位置。另一方面,如果您使用dbms_scheduler,则提前创建作业并简单地从过程中运行它们可能更容易(或使用dbms_scheduler 创建一个运行作业的链以响应其他一些动作或事件,例如将消息放入队列)。

当然,对于任何一种解决方案,您都需要构建基础架构来监控这三个作业的进度,前提是您关心它们何时以及是否成功(以及它们是否会产生错误)。

如果你要使用DBMS_SCHEDULER

无需使用动态 SQL。您可以放弃 EXECUTE IMMEDIATE 并直接调用 DBMS_SCHEDULER 包的程序,就像您调用任何其他程序一样。 调用RUN_JOB时,需要传入第二个参数。 use_current_session 参数控制作业是在当前会话(和块)中运行还是在单独的会话中运行(在这种情况下,当前会话可以继续执行其他操作)。由于您希望并行运行多个作业,因此您需要传入 false 的值。 虽然不是必需的,但更常规的做法是创建一次作业(将 auto_drop 设置为 false)然后从您的过程中运行它们。

所以你可能想在包之外创建作业,然后你的程序就变成了

CREATE PACKAGE BODY pkg IS
    CREATE PROCEDURE do
    IS
    BEGIN
        DBMS_SCHEDULER.RUN_JOB('job_other_pkg.other_proc', false);
        DBMS_SCHEDULER.RUN_JOB('job_other_pkg2.other_proc2', false);
        DBMS_SCHEDULER.RUN_JOB('job_other_pkg3.other_proc3', false);
    END;
END;

【讨论】:

谢谢@贾斯汀;你介意检查我的编辑,看看我是否正确地执行了 dbms_scheduler? @MatthewMoisen - 更新了我的答案,在dbms_scheduler 方面提出了一些建议。 太棒了;感谢您的回复。我只是在做动态 SQL,以免我写两行代码。 @MatthewMoisen - 请注意run_job 的第二个参数是布尔值而不是字符串。在您最近的更新中,您传递的是字符串而不是布尔值。 另一个问题:为什么 dbms_job.submit(null, '...'); 会导致错误,而 dbms_job.submit(l_jobno, '...'); ,其中 l_jobno 是未初始化的变量,不会导致错误?【参考方案2】:

另一个解决方案是破解 Oracle 的 SQL 并行机制。请参阅How to execute a stored procedure in a different session in same time in pl/sql 的回复。

它使用了威廉·罗伯逊 (William Robertson) 的出色解决方案 Parallel PL/SQL launcher。

(用Oracle 10g测试)

【讨论】:

以上是关于在 PL/SQL 中并行化调用的主要内容,如果未能解决你的问题,请参考以下文章

记一次重构:并行化调用接口实践

并行执行 oracle PL/SQL [重复]

如何在由 MPI 并行化的 fortran 中调用子例程?

如何并行化 python api 调用?

并行化多次调用异步函数

并行化 pandas pyodbc SQL 数据库调用