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 に通知されます。
2 番目の変更であるハッシュ パーティショニングの追加については、よくわかりません。これは、Oracle が作業負荷を分割するために使用する内部アルゴリズムに依存します。ハッシュ パーティションがある場合は、並列サーバー間でセグメントを分割するのがおそらく最も簡単です。パーティショニングを使用しない場合、少数のブロックしか存在しないため、Oracle はおそらく単一の並列サーバーですべてを実行するのが最も高速であると想定しています。
(ASSOCIATE STATISTICS
関数を使用してばかげたコストを与えたとしても、Oracle はそれをシリアルに実行します。おそらく、Oracle が複数の並列サーバー間でブロックを分割しないという制限があるのでしょうか?)
これは約1.1で動作します。私のマシンで数秒。しかし、それは(AFAIK)文書化されていない動作に依存しているため、同じように動作するかどうかはわかりません. Oracle のハッシュ関数は、単純なラウンドロビン方式で値をバケットに入れません。衝突を最小限に抑え、最適な並列処理の可能性を高めるには、多数のパーティションを使用する必要があります。
@David Aldridgeが述べたように、並列クエリは実際にはこのために設計されていません。より決定論的なプロセスが必要な場合は、@Polppan によって提案されたソリューションのようなものが必要になります (DBMS_SCHEDULER を使用)。