병렬처리
병렬처리 수행 과정 및 QC의 역할
1. 병렬 SQL이 시작되면 QC는 사용자가 지정한 병렬도(DOP, Degree Of Parallelism)와 오퍼레이션 종류에 따라 하나 또는 두개의 병렬 서버집합(Server Set)을 할당한다. 우선 서버풀(Parallel Execution Server Pool)로부터 필요한 만큼 서버 프로세스를 확보하고, 부족분은 새로 생성한다.
2. QC는 각 병렬서버에게 작업을 할당한다. 작업을 지시하고 일이 잘 진행되는지 관리,감독하는 작업반장의 역할이다.
3. 병렬로 처리하도록 사용자가 지시하지 않은 테이블은 QC가 직접 처리한다. 예를 들어, 아래와 같은 실행계획에서 dept테이블을 직렬로 읽어 병렬서버에 전송하는 8~9번 오퍼레이션은 QC의 몫이다.
4. QC는 각 병렬서버로부터의 산출물을 통합하는 작업을 수행한다. 예를 들어 집계함수(sum, avg, min, max 등)가 사용된 아래와 같은 병렬쿼리를 수행할 때, 각 병렬서버가 자신의 처리범위 내에서 집계(4번 단계)한 값을 QC에게 전송(3번 단계)하면 QC가 최종 집계 작업을 수행(1번 단계)한다.
5. QC는 쿼리의 최종 결과집합을 사용자에게 전송하며, DML일때는 갱신건수를 집계해서 전송해 준다. 쿼리결과를 전송하는 단계에서 수행되는 스칼라서브쿼리도 QC가 수행한다.
-- Release 10.2.0.2.0
SYS@oraSub3 AS SYSDBA> show parameter parallel
NAME TYPE VALUE
------------------------------------ ---------------------- ------------------------------
fast_start_parallel_rollback string LOW
parallel_adaptive_multi_user boolean TRUE
parallel_automatic_tuning boolean FALSE
parallel_execution_message_size integer 2148
parallel_instance_group string
parallel_max_servers integer 40
parallel_min_percent integer 0
parallel_min_servers integer 0
parallel_server boolean FALSE -- Deprecated
parallel_server_instances integer 1 -- Deprecated
parallel_threads_per_cpu integer 2
recovery_parallelism integer 0
-- Release 11.2.0.1.0
SQL> show parameter parallel
NAME TYPE VALUE
------------------------------------ ---------------------- ------------------------------
fast_start_parallel_rollback string LOW
parallel_adaptive_multi_user boolean TRUE
parallel_automatic_tuning boolean FALSE
parallel_degree_limit string CPU
parallel_degree_policy string MANUAL
parallel_execution_message_size integer 16384
parallel_force_local boolean FALSE
parallel_instance_group string
parallel_io_cap_enabled boolean FALSE -- Deprecated
parallel_max_servers integer 20
parallel_min_percent integer 0
parallel_min_servers integer 0
parallel_min_time_threshold string AUTO
parallel_server boolean FALSE -- Deprecated
parallel_server_instances integer 1 -- Deprecated
parallel_servers_target integer 8
parallel_threads_per_cpu integer 2
recovery_parallelism integer 0
병렬처리 실행 예제
SET AUTOT ON
SELECT /*+ ordered use_hash(d) full(d) full(e) noparallel(d) parallel(e 4) */
COUNT(*)
, MIN(sal)
, MAX(sal)
, AVG(sal)
, SUM(sal)
FROM dept d, emp e
WHERE d.loc = 'CHICAGO'
AND e.deptno = d.deptno
;
Execution Plan
----------------------------------------------------------
Plan hash value: 321505112
-------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | TQ |IN-OUT| PQ Distrib |
-------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 47 | 6 (17)| 00:00:01 | | | |
| 1 | SORT AGGREGATE | | 1 | 47 | | | | | |
| 2 | PX COORDINATOR | | | | | | | | |
| 3 | PX SEND QC (RANDOM) | :TQ10002 | 1 | 47 | | | Q1,02 | P->S | QC (RAND) |
| 4 | SORT AGGREGATE | | 1 | 47 | | | Q1,02 | PCWP | |
|* 5 | HASH JOIN | | 5 | 235 | 6 (17)| 00:00:01 | Q1,02 | PCWP | |
| 6 | BUFFER SORT | | | | | | Q1,02 | PCWC | |
| 7 | PX RECEIVE | | 1 | 21 | 3 (0)| 00:00:01 | Q1,02 | PCWP | |
| 8 | PX SEND HASH | :TQ10000 | 1 | 21 | 3 (0)| 00:00:01 | | S->P | HASH |
|* 9 | TABLE ACCESS FULL| DEPT | 1 | 21 | 3 (0)| 00:00:01 | | | |
| 10 | PX RECEIVE | | 14 | 364 | 2 (0)| 00:00:01 | Q1,02 | PCWP | |
| 11 | PX SEND HASH | :TQ10001 | 14 | 364 | 2 (0)| 00:00:01 | Q1,01 | P->P | HASH |
| 12 | PX BLOCK ITERATOR | | 14 | 364 | 2 (0)| 00:00:01 | Q1,01 | PCWC | |
| 13 | TABLE ACCESS FULL| EMP | 14 | 364 | 2 (0)| 00:00:01 | Q1,01 | PCWP | |
-------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
5 - access("E"."DEPTNO"="D"."DEPTNO")
9 - filter("D"."LOC"='CHICAGO')
Note
-----
- dynamic sampling used for this statement
Statistics
----------------------------------------------------------
24 recursive calls
0 db block gets
8 consistent gets
0 physical reads
0 redo size
390 bytes sent via SQL*Net to client
239 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
5 sorts (memory)
0 sorts (disk)
1 rows processed
Order By를 포함하는 병렬처리 실행 예제
SELECT /*+ full(고객) parallel(고객 4) */ *
FROM 고객
ORDER BY 고객명
;
그림 | DOP(병렬도) | p(병렬프로세스) | :TQ10000(S->P) | :TQ10001(P->P) | :TQ10002(P->S) |
---|---|---|---|---|---|
7-1 | 4 | 4 | 4 | 0 | 4 |
7-2 | 4 | 8(4*2) | 4 | 16(4^2) | 4 |
7-3 | 2 | 4(2*2) | 2 | 4(2^2) | 2 |
Order By 병렬처리 실행 예제
SELECT /*+ ordered use_hash(e) full(d) noparallel(d) full(e) parallel(e 2) pq_distribute(e broadcast none) */ *
FROM dept d, emp e
WHERE e.deptno = d.deptno
ORDER BY e.ename
;
Execution Plan
----------------------------------------------------------
Plan hash value: 709482007
--------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | TQ |IN-OUT| PQ Distrib |
--------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 14 | 1638 | 7 (29)| 00:00:01 | | | |
| 1 | PX COORDINATOR | | | | | | | | |
| 2 | PX SEND QC (ORDER) | :TQ10002 | 14 | 1638 | 7 (29)| 00:00:01 | Q1,02 | P->S | QC (ORDER) |
| 3 | SORT ORDER BY | | 14 | 1638 | 7 (29)| 00:00:01 | Q1,02 | PCWP | |
| 4 | PX RECEIVE | | 14 | 1638 | 6 (17)| 00:00:01 | Q1,02 | PCWP | |
| 5 | PX SEND RANGE | :TQ10001 | 14 | 1638 | 6 (17)| 00:00:01 | Q1,01 | P->P | RANGE |
|* 6 | HASH JOIN | | 14 | 1638 | 6 (17)| 00:00:01 | Q1,01 | PCWP | |
| 7 | BUFFER SORT | | | | | | Q1,01 | PCWC | |
| 8 | PX RECEIVE | | 4 | 120 | 3 (0)| 00:00:01 | Q1,01 | PCWP | |
| 9 | PX SEND BROADCAST | :TQ10000 | 4 | 120 | 3 (0)| 00:00:01 | | S->P | BROADCAST |
| 10 | TABLE ACCESS FULL| DEPT | 4 | 120 | 3 (0)| 00:00:01 | | | |
| 11 | PX BLOCK ITERATOR | | 14 | 1218 | 2 (0)| 00:00:01 | Q1,01 | PCWC | |
| 12 | TABLE ACCESS FULL | EMP | 14 | 1218 | 2 (0)| 00:00:01 | Q1,01 | PCWP | |
--------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
6 - access("E"."DEPTNO"="D"."DEPTNO")
Note
-----
- dynamic sampling used for this statement
Statistics
----------------------------------------------------------
191 recursive calls
3 db block gets
40 consistent gets
0 physical reads
632 redo size
1295 bytes sent via SQL*Net to client
239 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
8 sorts (memory)
0 sorts (disk)
14 rows processed
구분 | 명칭 | 설명 | (Intra/Inter)-Operation Parallelism | 오퍼레이션 |
---|---|---|---|---|
S->P | PARALLEL_FROM_SERIAL | QC가 읽은 데이터를 테이블 큐를 통해 병렬서버 프로세스에게 전송 | X | 직렬 |
P->S | PARALLEL_TO_SERIAL | 각 병렬서버 프로세스가 처리한 데이터를 QC에게 전송 | Inter | 병렬 |
P->P | PARALLEL_TO_PARALLEL | 데이터를 재분배(redistribution)하는 오퍼레이션 데이터를 정렬 또는 그룹핑하거나 조인을 위해 동적으로 파티셔닝할 때 사용 | Inter | 병렬 |
PCWP | PARALLEL_COMBINED_WITH_PARENT | 한 서버집합이 현재스텝과 부모스텝을 모두 처리 | Intra | 병렬 |
PCWC | PARALLEL_COMBINED_WITH_CHILD | 한 서버집합이 현재스텝과 자식스텝을 모두 처리 | Intra | 병렬 |
SERIAL | 공백인 경우 SERIAL 방식으로 처리 | X | 직렬 |
구분 | 내용 |
---|---|
RANGE | Order By 또는 Group By 를 병렬로 처리할 때 사용 정렬작업을 맡은 두번째 서버집합의 프로세스마다 처리범위를 지정하고 나서 데이터를 읽는 첫번째 서버집합이 정렬키값에 따라 정해진 범위에 해당하는 두번째 프로세스에게 분배하는 방식 QC는 작업범위를 할당하며, 정렬작업에는 참여하지 않는다. 정렬결과를 순서대로 받아서 사용자에게 전송하는 역할만 담당 |
HASH | 조인이나 Hash Group By 를 병렬로 처리할 때 사용 조인 키나 Group By 키값을 해시함수에 적용하여 리턴되는 값에 따라 데이터를 분배 P->P 뿐만 아니라 S->P 방식으로 이루어 질수도 있다. |
BROADCAST | QC 또는 첫번째 서버집합의 프로세스들이 각각 읽은 데이터를 두번째 서버집합의 "모든" 병렬프로세스에게 전송하는 방식 병렬 조인에서 크기가 매우 작은 테이블이 있을 때 사용되며 P->P 뿐만 아니라 S->P 방식으로 이루어 진다. 작은 테이블은 병렬로 읽지 않을 때가 많으므로 오히려 S->P가 일반적임 |
KEY | 특정 컬럼(들)을 기준으로 테이블 또는 인덱스를 파티셔닝할때 사용하는 분배 방식 실행계획에는 'PARTITION (KEY)'로 표시된다.(줄여서 'PART (KEY)'). |
ROUND-ROBIN | 파티션키, 정렬키, 해시함수에 의존하지 않고 반대편 정렬 서버에 무작위로 데이터 분배 골고루 분배되도록 ROUND-ROBIN 방식 사용 |
이벤트명 | 클래스 | 설명 | |||
---|---|---|---|---|---|
PX Deq: Execute Reply | Idle |
| |||
PX Deq: Execute Msg | Idle |
| PX Deq: Table Q Normal | Idle |
|
PX Deq Credit: send blkd | Other |
| |||
PX Deq Credit: need bulffer | Idle |
|
-- 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
여기서 t2 테이블은 병렬로 읽지만 t1으로의 insert는 직렬로 수행되고 있다.
이럴 때 t2를 읽어 QC에게 전송하는 4개의 병렬 서버들은 PX Deq Credit: send blkd 이벤트에서 자주 대기하게 됨.
insert 과정에서 병목(direct path write 대기 이벤트 발생)이 생기므로 select 문을 병렬로 수행하는 것은 불필요할 수 있음.
select 문을 직렬로 처리하면 PX Deq Credit: send blkd 이벤트는 사라짐.
병목을 해소함으로써 속도를 향상시키고 싶다면, 아래와 같이 t1으로의 insert도 병렬로 수행되게끔 함.
alter session enable parallel dml;
insert /*+ append parallel(t1 4) */ into t1
select /*+ full(t2) parallel(t2 4) */ * from t2;
insert를 담당한 1번 병렬 서버 집합은 아래에서 보듯 Direct Path Write를 수행하거나 2번 서버 집합으로부터 메시지 수신을 위해 대기(PX Deq: Table Q Normal 대기 이벤트)하고 있음.
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
select를 담당한 2번 병렬 서버 집합은 Direct Path Read를 수행하거나 1번 서버 집합으로 메시지를 송신하기 위해 대기(PX Deq Credit: send blkd) 하고 있음.