我有一个使用 Check-Function
的 SQL 语句,它需要很长时间才能执行。
现在我想并行化 Check-Function
的执行,但它不起作用。
我哪里错了?
下面的示例需要 5 秒来执行,但据我了解,由于并行性,它应该需要大约 1 秒。
测试代码片段:
CREATE TABLE PERSON AS
SELECT LEVEL AS ID, 'Person_'||LEVEL AS NAME
FROM DUAL
CONNECT BY LEVEL <= 5;
CREATE OR REPLACE FUNCTION LONGCHECKFUNC(ID NUMBER)
RETURN NUMBER IS
BEGIN
--Doing some very heavy Checks....
DBMS_LOCK.SLEEP(1 /*second*/);
RETURN 1;
END;
SELECT /*+PARALLEL(person, 5) */ *
FROM PERSON
WHERE LONGCHECKFUNC(ID)=1;
最佳答案
CREATE TABLE PERSON
PARTITION BY HASH(ID) PARTITIONS 16 /* <-- ADDED*/
AS
SELECT LEVEL AS ID, 'Person_'||LEVEL AS NAME
FROM DUAL
CONNECT BY LEVEL <= 5;
CREATE OR REPLACE FUNCTION LONGCHECKFUNC(ID NUMBER)
RETURN NUMBER PARALLEL_ENABLE /* <-- ADDED*/ IS
BEGIN
--Doing some very heavy Checks....
DBMS_LOCK.SLEEP(1 /*second*/);
RETURN 1;
END;
/
SELECT /*+PARALLEL(person, 5) */ *
FROM PERSON
WHERE LONGCHECKFUNC(ID)=1;
首先,您需要添加PARALLEL_ENABLE到你的功能。这告诉 Oracle,函数调用不共享任何 session 数据,并且可以独立运行。
第二个变化,加入hash分区,我不是很懂。这取决于 Oracle 用于划分工作负载的内部算法。当存在散列分区时,在并行服务器之间划分段可能是最简单的。没有分区,只有少量 block ,Oracle 可能认为在单个并行服务器上运行所有内容是最快的。
(即使您使用 ASSOCIATE STATISTICS
并为该函数提供可笑的成本,Oracle 仍会串行运行它。也许存在一些限制,Oracle 永远不会在多个并行服务器之间拆分一个 block ?)
这在大约 1.1 中运行。在我的机器上秒。但是由于它取决于(AFAIK)未记录的行为,我不确定它是否会为您运行相同的行为。 Oracle 的散列函数不会以简单的循环方式将值放入桶中。为了最大限度地减少冲突并增加最佳并行性的机会,您将需要使用大量分区。
正如@David Aldridge 提到的,并行查询并不是真正为此设计的。如果您想要一个更具确定性的过程,您将需要类似于@Polppan 建议的解决方案(使用 DBMS_SCHEDULER)。
关于sql - SQL语句中过程的并行执行(Oracle 11g),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13451944/