병렬 쿼리에서 사용자 정의 함수는 사용 방법과 실행 위치에 따라 동작이 달라질 수 있습니다.
테스트를 위해 아래와 같이 테이블을 생성하겠습니다.
-- 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 함수는 세션 ID를 반환합니다.
-- 2
CREATE OR REPLACE FUNCTION f1 (i_v1 IN NUMBER)
RETURN NUMBER
IS
BEGIN
RETURN SYS_CONTEXT ('USERENV', 'SID');
END;
/
아래 쿼리는 f1 함수를 사용합니다. PX 서버가 f1 함수를 수행하여 4개의 세션 ID가 반환됩니다.
-- 3
SELECT /*+ PARALLEL(4) */
f1 (c1) AS sid
FROM t1;
SID
---
71
71
11
11
191
191
131
131
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 함수를 사용합니다. QC가 f1 함수를 수행하여 1개의 세션 ID가 반환됩니다. 참고로 함수에 다른 값이 입력되어 스칼라 서브쿼리 캐싱이 작동하지 않았습니다.
-- 4
SELECT /*+ PARALLEL(4) */
(SELECT f1 (c1) FROM DUAL) AS sid
FROM t1;
SID
---
9
9
9
9
9
9
9
9
8 행이 선택되었습니다.
----------------------------------------------------------------------
| Id | Operation | Name | TQ |IN-OUT| PQ Distrib |
----------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | |
| 1 | FAST DUAL | | | | |
| 2 | PX COORDINATOR | | | | | -- !
| 3 | PX SEND QC (RANDOM)| :TQ10000 | Q1,00 | P->S | QC (RAND) |
| 4 | PX BLOCK ITERATOR | | Q1,00 | PCWC | |
| 5 | TABLE ACCESS FULL| T1 | Q1,00 | PCWP | |
----------------------------------------------------------------------
아래와 같이 ORDER BY 절을 사용하면 RANGE 데이터 분배가 발생합니다. 이로 인해 PX 서버가 f1 함수를 수행하여 4개의 세션 ID가 반환됩니다.
-- 5
SELECT /*+ PARALLEL(4) */
(SELECT f1 (c1) FROM DUAL) AS sid
FROM t1
ORDER BY sid;
SID
---
71
71
133
133
138
138
191
191
8 행이 선택되었습니다.
-------------------------------------------------------------------------
| Id | Operation | Name | TQ |IN-OUT| PQ Distrib |
-------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | |
| 1 | FAST DUAL | | | | |
| 2 | PX COORDINATOR | | | | |
| 3 | PX SEND QC (ORDER) | :TQ10001 | Q1,01 | P->S | QC (ORDER) |
| 4 | SORT ORDER BY | | Q1,01 | PCWP | |
| 5 | PX RECEIVE | | Q1,01 | PCWP | |
| 6 | PX SEND RANGE | :TQ10000 | Q1,00 | P->P | RANGE |
| 7 | PX BLOCK ITERATOR | | Q1,00 | PCWC | | -- !
| 8 | TABLE ACCESS FULL| T1 | Q1,00 | PCWP | |
-------------------------------------------------------------------------
아래와 같이 병합되지 않은 인라인 뷰 내에 스칼라 서브쿼리를 사용하면 PX 서버가 스칼라 서브쿼리를 수행하므로 4개의 세션 ID가 반환됩니다.
-- 6
SELECT /*+ PARALLEL(4) */
*
FROM (SELECT /*+ NO_MERGE */
(SELECT f1 (c1) FROM DUAL) AS sid
FROM t1);
SID
---
138
138
71
71
11
11
195
195
8 행이 선택되었습니다.
-----------------------------------------------------------------------
| Id | Operation | Name | TQ |IN-OUT| PQ Distrib |
-----------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | |
| 1 | FAST DUAL | | | | |
| 2 | PX COORDINATOR | | | | |
| 3 | PX SEND QC (RANDOM) | :TQ10000 | Q1,00 | P->S | QC (RAND) |
| 4 | VIEW | | Q1,00 | PCWP | |
| 5 | PX BLOCK ITERATOR | | Q1,00 | PCWC | | -- !
| 6 | TABLE ACCESS FULL| T1 | Q1,00 | PCWP | |
-----------------------------------------------------------------------