1. 병렬 SQL이 시작되면 QC는 사용자가 지정한 병렬도(DOP,degree of parallelism)와 오퍼레이션 종류에 따라 하나 또는 두 개의 병렬 서버 집합(Server Set)을 할당.
우선 서버 풀(Parallel Execution Server Pool)로부터 필요한 만큼 서버 프로세스를 확보하고, 부족분은 새로 생성.
2. QC는 각 병렬 서버에게 작업을 할당한다. 작업을 지시하고 일이 잘 진행되는지 관리- 감독하는 작업반장 역할.
3. 병렬로 처리하도록 사용자가 지시하지 않은 테이블은 QC가 직접 처리.
예를 들어, 아래 실행계획에서 dept 테이블을 직렬로 읽어 병렬 서버에 전송하는 8~9번 오퍼레이셔은 QC의 몫이다.
4. QC는 각 병렬 서버로부터의 산출물을 통합하는 작업을 수행한다. 예를 들어 집계 함수(sum,count,avg,min,max 등)가 사용된 아래와 같은 병렬 쿼리를 수행할 때,
각 병렬 서버가 자신의 처리 범위 내에서 집계(4번 단계)한 값을 QC에게 전송(3번 단계)하면 QC가 최종 집계 작업을 수행(1번 단계) 한다.
5. QC는 쿼리의 최종 결과집합을 사용자에게 전송하며, DML일 떄는 갱신 건수를 집계해서 전송해 준다. 쿼리 결과를 전송하는 단계에서 수행되는 스칼라 서브쿼리도 QC가 수행한다.
SELECT /*+ full(고객) parallel(고객 4) */ *
FROM 고객
ORDER BY 고객명
;
h5.S -> P : PARALLEL_FROM_SERIAL
h5.P -> S : PARALLEL_TO_SERIAL
in-out 오퍼레이션
1. S->P, P->S, P->P는 프로세스 간 통신이 발생한다
2. PCWP와 PCWC는 프로세스 간 통신이 발생하지 않으며, 각 병렬 서버가 독립적으로 여러 스텝을 처리할 때 나타난다. 하위 스텝의 출력값이 상위 스텝의 입력 값으로 사용된다.
3. P->P, P->S, PCWP, PCWC는 병렬 오퍼레이션인 반면, S->P는 직렬(Serial) 오퍼레이션이다
이벤트명 | 클래스 | 설명 |
---|---|---|
PX Deq: Execute Reply | Idle | QC가 각 병렬 서버에게 작업을 배분하고서 작업이 완료되기를 기다리는 상태 |
PX Deq: Execute Msg | Idle | 병렬 서버가 자신의 임무를 완수하고서 다른 병렬 서버가 일을 마치기를 기다리는 상태 QC 또는 소비자 병렬 서버에게 데이터 전송을 완료했을 때 나타남 |
PX Deq: Table Q Normal | Idle | 메세지 수신 대기. 메세지 큐에 데이터가 쌓이기를 기다리는 상태 |
PX Deq Credit: send blkd | Other | 메세지 송신 대기. QC 또는 소비자 병렬 서버에게 전송할 데이터가 있는데 블로킹 된 상태 생산자 프로세스가 메세지 큐를 통해 데이터를 전송하려고 하는데 어떤 이유에서건 소비자 프로세스가 버퍼에서 데이터를 빨리 꺼내가지 않을 때 발생 |
PX Deq Credit: need bulffer | Idle | 데이터를 전송하기 전에 상대편 병렬 서버 또는 QC로부터 credit 비트를 얻으려고 대기하는 상태 |
-- SESSION_1 수행
SELECT /*+ ORDERED USE_HASH(D) FULL(D) FULL(E) NOPARALLEL(D) PARALLEL(E 4) */
COUNT(*),
MIN(E.SAL),
MAX(E.SAL),
AVG(E.SAL),
SUM(E.SAL)
FROM DEPT D,
T_EMP E
WHERE D.LOC = 'CHICAGO'
AND E.DEPTNO = D.DEPTNO
;-- SESSION_2 수행
SELECT DECODE(A.QCSERIAL#, NULL, 'PAREMT', 'CHILD') ST_LVL,
A.SERVER_SET "SET",
A.SID,
A.SERIAL#,
STATUS,
EVENT,
WAIT_CLASS
FROM V$PX_SESSION A,
V$SESSION B
WHERE A.SID = B.SID
AND A.SERIAL# = B.SERIAL#
ORDER BY A.QCSID,
ST_LVL DESC,
A.SERVER_GROUP,
A.SERVER_SET
;ST_LVL SET SID SERIAL# STATUS EVENT WAIT_CLASS
------ --- ---- ------- -------- --------------------- ----------
PAREMT 7634 6110 ACTIVE PX Deq: Execute Reply Idle
CHILD 1 7647 574 ACTIVE direct path read User I/O
CHILD 1 7860 1083 ACTIVE direct path read User I/O
CHILD 1 7933 11436 ACTIVE direct path read User I/O
CHILD 1 7938 4284 ACTIVE direct path read User I/O
CHILD 1 7872 2783 INACTIVE PX Deq: Execution Msg Idle
CHILD 1 7801 2574 INACTIVE PX Deq: Execution Msg Idle
insert /*+ append */ into t1
select /*+ full(t2) parallel(t2 4) */ * from t2
alter session enable parallel dml;
insert /*+ append parallel(t1 4) */ into t1
select /*+ full(t2) parallel(t2 4) */ * from t2;
ST_LVL SET SID SERIAL# STATUS EVENT WAIT_CLASS
------ --- ---- ------- -------- ----------------------------------------
PARENT QC 2643 46632 ACTIVE PX Deq: Execute Reply Idle
CHILD 1 2778 22712 ACTIVE direct path write User I/O
CHILD 1 2753 37169 ACTIVE direct path write User I/O
CHILD 1 3096 52396 ACTIVE PX Deq: Table Q Normal User I/O
CHILD 1 2483 6508 ACTIVE direct path write User I/O
CHILD 1 2512 21611 ACTIVE direct path read Idle
CHILD 1 2822 38188 ACTIVE PX Deq Credit: send blkd Idle
CHILD 1 2492 18064 ACTIVE direct path read Idle
CHILD 1 3186 29287 ACTIVE PX Deq Credit: send blkd Idle
테이블이 생성되었습니다.
SQL> exec dbms_stats.gather_table_stats(user, '고객');
PL/SQL 처리가 정상적으로 완료되었습니다.
{CODE}
...
1000 개의 행이 선택되었습니다.
SQL>
SQL> break on dfo_no on tq_id on server_type
SQL> SELECT tq_id
2 , server_type
3 , process
4 , num_rows
5 , bytes
6 , waits
7 FROM v$pq_tqstat
8 ORDER BY dfo_number
9 , tq_id
10 , DECODE(SUBSTR(server_type, 1, 4), 'Rang', 1, 'Prod', 2, 'Cons', 3)
11 , process
12 ;
TQ_ID SERVER_TYPE PROCESS NUM_ROWS BYTES WAITS
8 개의 행이 선택되었습니다.
{CODE}
Execution Plan
Id | Operation | Name | Rows | Bytes | Cost (%CPU) | Time | TQ | IN-OUT | PQ Distrib |
0 | SELECT STATEMENT | 10 | 30 | 3 (34) | 00:00:01 | ||||
1 | PX COORDINATOR | ||||||||
2 | PX SEND QC (RANDOM) | :TQ10001 | 10 | 30 | 3 (34) | 00:00:01 | Q1,01 | P->S | QC (RAND) |
3 | HASH GROUP BY | 10 | 30 | 3 (34) | 00:00:01 | Q1,01 | PCWP | ||
4 | PX RECEIVE | 10 | 30 | 3 (34) | 00:00:01 | Q1,01 | PCWP | ||
5 | PX SEND HASH | :TQ10000 | 10 | 30 | 3 (34) | 00:00:01 | Q1,00 | P->P | HASH |
6 | HASH GROUP BY | 10 | 30 | 3 (34) | 00:00:01 | Q1,00 | PCWP | ||
7 | PX BLOCK ITERATOR | 1000 | 3000 | 2 (0) | 00:00:01 | Q1,00 | PCWC | ||
8 | TABLE ACCESS FULL | 고객 | 1000 | 3000 | 2 (0) | 00:00:01 | Q1,00 | PCWP |
고객등급 CNT
10 개의 행이 선택되었습니다.
SQL> break on dfo_no on tq_id on server_type
SQL> SELECT tq_id
2 , server_type
3 , process
4 , num_rows
5 , bytes
6 , waits
7 FROM v$pq_tqstat
8 ORDER BY dfo_number
9 , tq_id
10 , DECODE(SUBSTR(server_type, 1, 4), 'Rang', 1, 'Prod', 2, 'Cons', 3)
11 , process
12 ;
TQ_ID SERVER_TYPE PROCESS NUM_ROWS BYTES WAITS
7 개의 행이 선택되었습니다.
{CODE}
COLUMN_NAME NUM_DISTINCT NUM_NULLS SELECTIVITY CARDINALITY