3

我有一个 SQL 语句,它使用一个Check-Function需要很长时间才能执行的语句。

现在我想并行化 的执行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;
4

2 回答 2

1

并行查询不是为这种尝试的功能而设计的。

这里最好的做法是开始调整函数本身。

于 2012-11-19T10:54:38.413 回答
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 函数调用不共享任何会话数据,并且可以独立运行。

第二个变化,添加哈希分区,我不太明白。它取决于 Oracle 用来划分工作负载的内部算法。当存在散列分区时,在并行服务器之间划分段可能是最简单的。如果没有分区,则只有少量块,Oracle 可能认为在单个并行服务器上运行所有内容是最快的。

(即使你使用ASSOCIATE STATISTICS这个函数并给它一个荒谬的成本,Oracle 仍然会串行运行它。也许有一些限制,Oracle 永远不会在多个并行服务器之间分割一个块?)

这在大约 1.1 中运行。在我的机器上秒。但由于它取决于(AFAIK)未记录的行为,我不确定它是否会为你运行同样的。Oracle 的散列函数不会以简单的循环方式将值放入桶中。为了最大限度地减少冲突并增加最佳并行性的机会,您将需要使用大量分区。

正如@David Aldridge 提到的,并行查询并不是真正为此设计的。如果您想要一个更具确定性的过程,您将需要类似@Polppan 建议的解决方案(使用 DBMS_SCHEDULER)。

于 2012-11-20T06:05:03.227 回答