我准备了一些小提琴:
CREATE TABLE t_process
("process_number" int, "process_status" varchar2(12))
;
INSERT ALL
INTO t_process ("process_number", "process_status")
VALUES (1, 'PROCESSING')
INTO t_process ("process_number", "process_status")
VALUES (2, 'PROCESSING')
INTO t_process ("process_number", "process_status")
VALUES (3, 'TO_BE_KILLED')
INTO t_process ("process_number", "process_status")
VALUES (4, 'PROCESSING')
INTO t_process ("process_number", "process_status")
VALUES (5, 'PROCESSING')
INTO t_process ("process_number", "process_status")
VALUES (6, 'TO_BE_KILLED')
INTO t_process ("process_number", "process_status")
VALUES (7, 'TO_BE_KILLED')
INTO t_process ("process_number", "process_status")
VALUES (8, 'WAITING')
INTO t_process ("process_number", "process_status")
VALUES (9, 'KILLED')
SELECT * FROM dual
;
这是我的处理程序:
CREATE OR REPLACE PROCEDURE MY_PROCEDURE(IN_ID IN NUMBER) IS
BEGIN
UPDATE T_PROCESS SET process_status = 'KILLING' WHERE process_number = IN_ID;
COMMIT;
-- DO SOME STUFF
UPDATE T_PROCESS SET process_status = 'KILLED' WHERE process_number = IN_ID;
COMMIT;
END MY_PROCEDURE;
现在我想使用DBMS_PARALLEL_EXECUTE
来运行这个自定义SQL
:
DECLARE
id1 number = :id1;
id2 number = :id2;
BEGIN
MY_PROCEDURE(id1);
END;
所以,我的问题是:
我可以使用DBMS_PARALLEL_EXECUTE
执行上述SQL语句吗
因为我只找到了UPDATE
的例子。也许CREATE_CHUNKS_BY_SQL
只选择TO_BE_KILLED
,然后用上面的语句选择RUN_TASK
?
是的,你可以很好地做到11g以后。我很惊讶为什么这里没有建议。
您可以在run_task中执行类似begin MY_PROCEDURE( :start_id, :end_id ); end;
的过程
您可能需要修改过程以接受两个参数:start_id,:end_id
这是示例代码(基于"create_chuns_by_rowid")。
DECLARE
l_task VARCHAR2(30) := 'parallel_processing';
l_sql_stmt VARCHAR2(32767);
l_try NUMBER;
l_status NUMBER;
BEGIN
DBMS_PARALLEL_EXECUTE.create_task (task_name => l_task);
DBMS_PARALLEL_EXECUTE.create_chunks_by_rowid(task_name => l_task,
table_owner => 'SCHEMANAME',
table_name => 'T_PROCESS',
by_row => TRUE,
chunk_size => 10000);
l_sql_stmt := 'begin MY_PROCEDURE( :start_id, :end_id ); end;';
DBMS_PARALLEL_EXECUTE.run_task(task_name => l_task,
sql_stmt => l_sql_stmt,
language_flag => DBMS_SQL.NATIVE,
parallel_level => 10);
-- If there is error, RESUME it for at most 2 times.
l_try := 0;
l_status := DBMS_PARALLEL_EXECUTE.task_status(l_task);
WHILE(l_try < 2 and l_status != DBMS_PARALLEL_EXECUTE.FINISHED)
Loop
l_try := l_try + 1;
DBMS_PARALLEL_EXECUTE.resume_task(l_task);
l_status := DBMS_PARALLEL_EXECUTE.task_status(l_task);
END LOOP;
DBMS_PARALLEL_EXECUTE.drop_task(l_task);
END;
/
根据您的情况/舒适度,您也可以通过以下方式create chunks
。
CREATE_CHUNKS_BY_NUMBER_COL
——如果要通过"process_number"进行更新
CREATE_CHUNKS_BY_SQL
——如果您认为BY_SQL将为您提供一组非常小的块来进行处理。注意,在这种方法中,每个块将能够处理每个块仅1行的事实(每个块的start_id和end_id相同)。
没有(或者至少没有真正的肮脏黑客)。如果你想并行执行PL/SQL,我已经学会了以下选项:
- 使用dbms_job。您已经用许可证支付了费用,许多DBA都了解它,如果您没有太高的监管、审计、安全或维护要求,它的工作是合理的。你必须自己建造。它从1995年左右就已经存在了
- 使用红木的Cronacle。这是我20年前的第一份工作,美好的回忆。它允许您使用Oracle类似的语法在Oracle上轻松地跨集群运行作业,而且它比dbms_job更可靠,具有更好的日志记录功能,还可以运行操作系统语句,以及进行打印。但这需要花钱
- 使用Invantive Scheduler。我目前在那里工作,它与Cronacle类似,但针对的是行政系统。当我无法轻松访问操作系统、文件,尤其是dbms_output等的日志记录时,我讨厌安排复杂的作业
- 使用特定于应用程序的调度程序。例如,Oracle电子商务套件提供了一个很好的调度器,具有安全性、互斥性、合理的日志记录等功能。如果您已经有了这样的软件包,它的使用通常是免费的,您的应用程序管理员也有使用经验
当你是一名程序员,还没有标准,也不需要更多的并行处理时,你可以选择dbms_job。当容量增加或有更多功能需求时,请选择更好的解决方案。