병렬 쿼리에서 패키지 변수를 사용한 사용자 정의 함수는 PARALLEL_ENABLE 키워드의 기술 여부에 따라 동작이 달라질 수 있습니다.
테스트를 위해 아래와 같이 테이블을 생성하겠습니다.
-- 1
DROP TABLE t1 PURGE;
CREATE TABLE t1 AS SELECT ROWNUM AS c1, LPAD ('X', 4000, 'X') AS c2 FROM XMLTABLE ('1 to 8');
아래 f1, f2 함수는 세션 ID와 pkg1.gv1 패키지 변수에 1을 더한 값을 반환합니다. 아울러 f2 함수에만 PARALLEL_ENABLE 키워드를 사용합니다.
-- 2-1
DROP PACKAGE pkg1;
CREATE OR REPLACE PACKAGE pkg1
IS
gv1 NUMBER := 0;
END;
/
-- 2-2
CREATE OR REPLACE FUNCTION f1 (i_v1 IN NUMBER)
RETURN VARCHAR2
IS
BEGIN
pkg1.gv1 := pkg1.gv1 + 1;
RETURN SYS_CONTEXT ('USERENV', 'SID') || ',' || pkg1.gv1;
END;
/
-- 2-3
CREATE OR REPLACE FUNCTION f2 (i_v1 IN NUMBER)
RETURN VARCHAR2
PARALLEL_ENABLE
IS
BEGIN
pkg1.gv1 := pkg1.gv1 + 1;
RETURN SYS_CONTEXT ('USERENV', 'SID') || ',' || pkg1.gv1;
END;
/
아래 쿼리는 QC가 f1 함수를 수행하여 1개의 세션 ID가 반환됩니다. 패키지 변수는 세션 레벨에서 할당되므로 일관된 결과를 보장하기 위해 QC가 f1 함수를 실행한 것입니다.
-- 3
SELECT /*+ PARALLEL(4) */
f1 (c1) AS sid
FROM t1;
SID
-----
277,1
277,2
277,3
277,4
277,5
277,6
277,7
277,8
8 행이 선택되었습니다.
----------------------------------------------------------------------
| Id | Operation | Name | TQ |IN-OUT| PQ Distrib |
----------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | |
| 1 | PX COORDINATOR | | | | | -- !
| 2 | PX SEND QC (RANDOM)| :TQ10000 | Q1,00 | P->S | QC (RAND) |
| 3 | PX BLOCK ITERATOR | | Q1,00 | PCWC | |
| 4 | TABLE ACCESS FULL| T1 | Q1,00 | PCWP | |
----------------------------------------------------------------------
아래 쿼리는 병합되지 않은 인라인 뷰 내에 f1 함수를 사용합니다. 실행 계획 1번에 PX COORDINATOR FORCED SERIAL 오퍼레이션이 표시됩니다. QC가 f1 함수를 수행하여 1개의 세션 ID가 반환되고 앞선 쿼리에 이어서 1씩 증가한 pkg1.gv1 패키지 변수 값이 반환됩니다.
-- 4
SELECT /*+ PARALLEL(4) */
*
FROM (SELECT /*+ NO_MERGE */
f1 (c1) AS sid
FROM t1);
SID
------
277,9
277,11
277,12
277,13
277,14
277,15
277,16
277,17
8 행이 선택되었습니다.
------------------------------------------------------------------------------
| Id | Operation | Name | TQ |IN-OUT| PQ Distrib |
------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | |
| 1 | PX COORDINATOR FORCED SERIAL| | | | | -- !
| 2 | PX SEND QC (RANDOM) | :TQ10000 | Q1,00 | P->S | QC (RAND) |
| 3 | VIEW | | Q1,00 | PCWP | |
| 4 | PX BLOCK ITERATOR | | Q1,00 | PCWC | |
| 5 | TABLE ACCESS FULL | T1 | Q1,00 | PCWP | |
------------------------------------------------------------------------------
아래 쿼리는 PX 서버가 f2 함수를 수행하여 4개의 세션 ID가 반환됩니다. 함수에 PARALLEL_ENABLE 키워드를 사용하면 PX 서버 세션에 pkg1.gv1 패키지 변수가 할당됩니다. 이로 인해 세션 ID 별로 1씩 증가한 pkg1.gv1 패키지 변수 값이 반환됩니다.
-- 5
SELECT /*+ PARALLEL(4) */
f2 (c1) AS sid
FROM t1;
SID
-----
22,1
22,2
394,1
394,2
267,1
267,2
395,1
395,2
8 행이 선택되었습니다.
----------------------------------------------------------------------
| Id | Operation | Name | TQ |IN-OUT| PQ Distrib |
----------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | |
| 1 | PX COORDINATOR | | | | |
| 2 | PX SEND QC (RANDOM)| :TQ10000 | Q1,00 | P->S | QC (RAND) |
| 3 | PX BLOCK ITERATOR | | Q1,00 | PCWC | | -- !
| 4 | TABLE ACCESS FULL| T1 | Q1,00 | PCWP | |
----------------------------------------------------------------------
아래 쿼리는 병합되지 않은 인라인 뷰 내에 f2 함수를 사용합니다. 새로운 PX 서버 세션에 pkg1.gv1 패키지 변수가 할당되므로 세션 ID 별로 1씩 증가한 pkg1.gv1 패키지 변수 값이 반환됩니다.
-- 6
SELECT /*+ PARALLEL(4) */
*
FROM (SELECT /*+ NO_MERGE */
f2 (c1) AS sid
FROM t1);
SID
-----
395,1
395,2
22,1
22,2
394,1
394,2
267,1
267,2
8 행이 선택되었습니다.
-----------------------------------------------------------------------
| Id | Operation | Name | TQ |IN-OUT| PQ Distrib |
-----------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | |
| 1 | PX COORDINATOR | | | | |
| 2 | PX SEND QC (RANDOM) | :TQ10000 | Q1,00 | P->S | QC (RAND) |
| 3 | VIEW | | Q1,00 | PCWP | | -- !
| 4 | PX BLOCK ITERATOR | | Q1,00 | PCWC | |
| 5 | TABLE ACCESS FULL| T1 | Q1,00 | PCWP | |
-----------------------------------------------------------------------