☞ 병렬 처리란?

  • SQL문에 수행해야 할 작업 범위를 여러 개의 작은 단위로 나누어 여러 프로세스가 동시에 처리하는 것을 말함

\- 그림7-1 참조

1. Query Coordinator와 병렬 서버 프로세스

1) 설명

  • Query Coordinator(이하 QC)는 병렬 SQL문을 수행한 세션을 의미하며, 병렬 서버 프로세스는 실제 작업을 수행하는 세션을 의미
  • QC의 역할

1. 병렬 SQL이 시작되면 QC는 사용자가 지정한 PARALLEL 개수와 오퍼레이션 종류에 따라 하나 또는 두 개의 병렬 서버 집합을 할당.
   그리고 서버 풀(parallel_min_servers 파라미터로 설정된 만큼의 병렬 프로세스를 오라클이 기본적으로 생성해 서버 풀에 담아 둠)로부터
   필요한 만큼 서버 프로세스를 확보하고, 부족분은 새로 생성함

2. QC는 각 병렬 서버에게 작업을 할당하고 관리 감독한다.

3. 병렬로 처리하도록 사용자가 지시하지 않은 테이블은 QC가 직접 처리함.
   아래의 실행계획에서 DEPT 테이블을 직렬로 읽어 병렬 서버에 전송하는 8~9번 오퍼레이션은 QC 몫

4. QC는 각 병렬 서버로부터의 산출물을 통합하는 작업을 수행함.
   아래의 실행계획에서, 집계 함수를 수행할 때 각 병렬 서버가 자신의 처리 범위 내에서 집계(4번)한 값을 QC에게 전송(3번)하면, QC가 최종 집계(1번)을 한다.

5. QC는 쿼리의 최종 결과집합을 사용자에게 전송하며, DML일 경우 갱신 건수를 집계해서 전송. 전송 단계에서는 스칼라 서브쿼리도 QC가 수행함.

2) 테스트


-- 오라클 버전
SELECT * FROM v$version
;

BANNER
------------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.2.0.3.0 - 64bit
PL/SQL Release 10.2.0.3.0 - Production

-- EMP, DEPT 테이블 생성
CREATE TABLE EMP
       (EMPNO NUMBER(4) NOT NULL,
        ENAME VARCHAR2(10),
        JOB VARCHAR2(9),
        MGR NUMBER(4),
        HIREDATE DATE,
        SAL NUMBER(7, 2),
        COMM NUMBER(7, 2),
        DEPTNO NUMBER(2));

INSERT INTO EMP VALUES
        (7369, 'SMITH',  'CLERK',     7902,
        TO_DATE('17-DEC-1980', 'DD-MON-YYYY'),  800, NULL, 20);
INSERT INTO EMP VALUES
        (7499, 'ALLEN',  'SALESMAN',  7698,
        TO_DATE('20-FEB-1981', 'DD-MON-YYYY'), 1600,  300, 30);
INSERT INTO EMP VALUES
        (7521, 'WARD',   'SALESMAN',  7698,
        TO_DATE('22-FEB-1981', 'DD-MON-YYYY'), 1250,  500, 30);
INSERT INTO EMP VALUES
        (7566, 'JONES',  'MANAGER',   7839,
        TO_DATE('2-APR-1981', 'DD-MON-YYYY'),  2975, NULL, 20);
INSERT INTO EMP VALUES
        (7654, 'MARTIN', 'SALESMAN',  7698,
        TO_DATE('28-SEP-1981', 'DD-MON-YYYY'), 1250, 1400, 30);
INSERT INTO EMP VALUES
        (7698, 'BLAKE',  'MANAGER',   7839,
        TO_DATE('1-MAY-1981', 'DD-MON-YYYY'),  2850, NULL, 30);
INSERT INTO EMP VALUES
        (7782, 'CLARK',  'MANAGER',   7839,
        TO_DATE('9-JUN-1981', 'DD-MON-YYYY'),  2450, NULL, 10);
INSERT INTO EMP VALUES
        (7788, 'SCOTT',  'ANALYST',   7566,
        TO_DATE('09-DEC-1982', 'DD-MON-YYYY'), 3000, NULL, 20);
INSERT INTO EMP VALUES
        (7839, 'KING',   'PRESIDENT', NULL,
        TO_DATE('17-NOV-1981', 'DD-MON-YYYY'), 5000, NULL, 10);
INSERT INTO EMP VALUES
        (7844, 'TURNER', 'SALESMAN',  7698,
        TO_DATE('8-SEP-1981', 'DD-MON-YYYY'),  1500,    0, 30);
INSERT INTO EMP VALUES
        (7876, 'ADAMS',  'CLERK',     7788,
        TO_DATE('12-JAN-1983', 'DD-MON-YYYY'), 1100, NULL, 20);
INSERT INTO EMP VALUES
        (7900, 'JAMES',  'CLERK',     7698,
        TO_DATE('3-DEC-1981', 'DD-MON-YYYY'),   950, NULL, 30);
INSERT INTO EMP VALUES
        (7902, 'FORD',   'ANALYST',   7566,
        TO_DATE('3-DEC-1981', 'DD-MON-YYYY'),  3000, NULL, 20);
INSERT INTO EMP VALUES
        (7934, 'MILLER', 'CLERK',     7782,
        TO_DATE('23-JAN-1982', 'DD-MON-YYYY'), 1300, NULL, 10);

CREATE TABLE DEPT
       (DEPTNO NUMBER(2),
        DNAME VARCHAR2(14),
        LOC VARCHAR2(13) );

INSERT INTO DEPT VALUES (10, 'ACCOUNTING', 'NEW YORK');
INSERT INTO DEPT VALUES (20, 'RESEARCH',   'DALLAS');
INSERT INTO DEPT VALUES (30, 'SALES',      'CHICAGO');
INSERT INTO DEPT VALUES (40, 'OPERATIONS', 'BOSTON');

COMMIT;
/

CREATE UNIQUE INDEX EMP_U1 ON EMP (EMPNO);

CREATE INDEX EMP_N1 ON EMP (DEPTNO);

CREATE UNIQUE INDEX DEPT_U1 ON DEPT (DEPTNO);

CREATE INDEX DEPT_N1 ON DEPT (LOC);

BEGIN
  DBMS_STATS.GATHER_TABLE_STATS(USER,
                                'EMP',
                                CASCADE => TRUE);
END;
/

BEGIN
  DBMS_STATS.GATHER_TABLE_STATS(USER,
                                'DEPT',
                                CASCADE => TRUE);
END;
/

-- 테스트
EXPLAIN PLAN FOR
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,
       EMP  E
WHERE  D.LOC    = 'CHICAGO'
AND    E.DEPTNO = D.DEPTNO
;

@xplan
-------------------------------------------------------------------------------------------------------------------
| Id  | Operation                 | Name     | Rows  | Bytes | Cost (%CPU)| Time     |    TQ  |IN-OUT| PQ Distrib |
-------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT          |          |     1 |    18 |     8  (13)| 00:00:01 |        |      |            |
|   1 |  SORT AGGREGATE           |          |     1 |    18 |            |          |        |      |            |
|   2 |   PX COORDINATOR          |          |       |       |            |          |        |      |            |
|   3 |    PX SEND QC (RANDOM)    | :TQ10002 |     1 |    18 |            |          |  Q1,02 | P->S | QC (RAND)  |
|   4 |     SORT AGGREGATE        |          |     1 |    18 |            |          |  Q1,02 | PCWP |            |
|*  5 |      HASH JOIN            |          |    14 |   252 |     8  (13)| 00:00:01 |  Q1,02 | PCWP |            |
|   6 |       BUFFER SORT         |          |       |       |            |          |  Q1,02 | PCWC |            |
|   7 |        PX RECEIVE         |          |     2 |    22 |     5   (0)| 00:00:01 |  Q1,02 | PCWP |            |
|   8 |         PX SEND HASH      | :TQ10000 |     2 |    22 |     5   (0)| 00:00:01 |        | S->P | HASH       |
|*  9 |          TABLE ACCESS FULL| DEPT     |     2 |    22 |     5   (0)| 00:00:01 |        |      |            |
|  10 |       PX RECEIVE          |          |    28 |   196 |     2   (0)| 00:00:01 |  Q1,02 | PCWP |            |
|  11 |        PX SEND HASH       | :TQ10001 |    28 |   196 |     2   (0)| 00:00:01 |  Q1,01 | P->P | HASH       |
|  12 |         PX BLOCK ITERATOR |          |    28 |   196 |     2   (0)| 00:00:01 |  Q1,01 | PCWC |            |
|  13 |          TABLE ACCESS FULL| EMP      |    28 |   196 |     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')

26 rows selected.
;

-- QC를 보기위한 작업
-- EMP 테이블 복제한 테이블 생성
CREATE TABLE T_EMP AS
SELECT *
FROM   EMP,
       (SELECT ROWNUM NO
        FROM   DUAL
        CONNECT BY LEVEL <= 100000);

-- 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 LPAD(NVL(TO_CHAR(PS.SERVER#), 'Main'), 5, ' ') CLASS,
       PS.SID || ', ' || PS.SERIAL# AS SID_SERIAL,
       PS.QCSID,
       PS.DEGREE,
       SUBSTR(S.STATUS, 1, 1) AS STATUS,
       P.SPID SPID,
       DECODE(SUBSTR(S.ACTION, 1, 4),
              'FRM:',
              SUBSTR(S.MODULE, 1, 15) || '(Form)',
              'Onli',
              SUBSTR(S.MODULE, 1, 15) || '(Form)',
              'Conc',
              SUBSTR(S.MODULE, 1, 15) || '(Conc)',
              SUBSTR(S.MODULE, 1, 20)) AS MODULE,
       SUBSTR(S.PROGRAM, -6, 6) PROGRAM,
       SUBSTR(SW.EVENT, 1, 30) WAIT,
       LAST_CALL_ET LAST_CALL_ET,
       (SELECT SUBSTR(SQL_TEXT, 1, 50)
        FROM   V$SQL SQ
        WHERE  SQ.ADDRESS = S.SQL_ADDRESS
        AND    SQ.HASH_VALUE = S.SQL_HASH_VALUE
        AND    ROWNUM = 1) SQL_TEXT,
       NVL(PS.SERVER#, 0) AS SERVER_NUM
FROM   V$SESSION      S,
       V$PROCESS      P,
       V$SESSION_WAIT SW,
       V$PX_SESSION   PS
WHERE  S.PADDR   = P.ADDR
AND    SW.SID    = S.SID
AND    S.SID     = PS.SID
AND    S.SERIAL# = PS.SERIAL#
AND    NOT EXISTS (SELECT 1
                   FROM   V$BGPROCESS BP
                   WHERE  P.ADDR = BP.PADDR)
ORDER  BY PS.QCSID,
          DEGREE NULLS FIRST,
          SUBSTR(S.PROGRAM, -6, 6) NULLS FIRST,
          CLASS
;

CLASS SID,Serial#   QCSID DEGREE S SPID     MODULE   PROGRAM  WAIT                  LCE SQL_TEXT                                           SERVER_NUM
----- ------------ ------ ------ - -------- -------- -------- --------------------- --- -------------------------------------------------- ----------
 Main 9851, 75       9851        A 376910   SQL*Plus sw.exe   PX Deq: Execute Reply   0 SELECT /*+ ORDERED USE_HASH(D) FULL(D) FULL(E) NOP          0  <-- QC
    1 9875, 102      9851      4 A 418678   SQL*Plus (P000)   direct path read        0 SELECT /*+ ORDERED USE_HASH(D) FULL(D) FULL(E) NOP          1  <-- SP-1
    2 9766, 11       9851      4 A 180228   SQL*Plus (P001)   direct path read        0 SELECT /*+ ORDERED USE_HASH(D) FULL(D) FULL(E) NOP          2  <-- SP-2
    3 9754, 199      9851      4 A 438880   SQL*Plus (P002)   direct path read        0 SELECT /*+ ORDERED USE_HASH(D) FULL(D) FULL(E) NOP          3  <-- SP-3
    4 9758, 91       9851      4 A 475718   SQL*Plus (P003)   direct path read        0 SELECT /*+ ORDERED USE_HASH(D) FULL(D) FULL(E) NOP          4  <-- SP-4

2. Intra-Operation Parallelism과 Inter-Operation Parallelism


SELECT /*+ FULL(고객) PARALLEL(고객 4) */
       *
FROM   고객
ORDER BY 고객명
;

\- 그림 7_2 참조


1. 이해를 돕기 위해, 8명의 영업사원이 각자 관리하던 명함을 영업팀에서 통합 관리할 목적으로 명함 전체를 이름순으로 정렬하는 경우,
   두 가지 방법을 생각해 볼 수 있음.
   첫번째 방법은, 8명 각자 자신의 것을 정렬하고 이를 영업팀장이 최종적으로 Merge하는 방법이 있다.
   두번째는, 2개조로 나누고 역할을 분담해 서로 다른 작업을 동새에 진행하는 것인데, 영업팀장은 관리를(QC) 하고,
   4명은 분배, 4명은 분배된 내용을 정렬하는 방법이다.

2. 정렬팀은 먼저 알파벳 순으로 1/4 배분을 받고, 분배팀은 QC로부터 할당받은 뭉치를 정렬팀에게 보내서, 결과적으로 정렬팀이
   자신의 분배범위 내에서만 정렬하고, 최종적으로 이 4개만 MERGE하면 된다.

3. 첫 번째 방법은 작업자가 많을수록 최종 QC가 머지하는 단계에서 부하가 걸리므로, 오라클은 ORDER BY일 경우 두 번째 방식을
   사용한다.

4. 이때, 이렇게 동시에 처리하는 것을 'Intra-Operation Parallelism'이라고 하고, 작업을 다른조에 분배하거나 QC에게 전송하는
   작업을 동시에 처리하는 것을 'Inter-Operation Parallelism'라고 함.
   차이점은 'Intra-Operation Parallelism'은 프로세스간 통신이 필요 없고, 'Inter-Operation Parallelism'은 프로세스간 통신이 필요함.

3. 테이블 큐(Table Queue)

1) 테이블 큐란?

\- 그림 7_3 참조

  • 테이블 큐란, 쿼리 서버 집합 간(P->P) 또는 QC와 쿼리 서버 집합 간(P->S, S->P) 데이터 전송을 위해 연결된 파이프 라인(Pipeline)을 의미함.
    그리고 그림 7_3에서 보듯, 큐에 부여된 :TQ10000, :TQ10001, :TQ10002와 같은 이름을 '테이블 큐 식별자(TQ Identifier)'라고 함.

EXPLAIN PLAN FOR
SELECT /*+ ORDERED USE_HASH(D) FULL(D) FULL(E) NOPARALLEL(D) PARALLEL(E 2) PQ_DISTRIBUTE(E BROADCAST NONE) */
       *
FROM   DEPT D,
       EMP  E
WHERE  E.DEPTNO = D.DEPTNO
ORDER BY E.ENAME
;

@xplan
--------------------------------------------------------------------------------------------------------------------
| Id  | Operation                  | Name     | Rows  | Bytes | Cost (%CPU)| Time     |    TQ  |IN-OUT| PQ Distrib |
--------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT           |          |    14 |   798 |     9  (12)| 00:00:01 |        |      |            |
|   1 |  PX COORDINATOR            |          |       |       |            |          |        |      |            |
|   2 |   PX SEND QC (ORDER)       | :TQ10002 |    14 |   798 |     9  (12)| 00:00:01 |  Q1,02 | P->S | QC (ORDER) |
|   3 |    SORT ORDER BY           |          |    14 |   798 |     9  (12)| 00:00:01 |  Q1,02 | PCWP |            |
|   4 |     PX RECEIVE             |          |    14 |   798 |     8   (0)| 00:00:01 |  Q1,02 | PCWP |            |
|   5 |      PX SEND RANGE         | :TQ10001 |    14 |   798 |     8   (0)| 00:00:01 |  Q1,01 | P->P | RANGE      |
|*  6 |       HASH JOIN            |          |    14 |   798 |     8   (0)| 00:00:01 |  Q1,01 | PCWP |            |
|   7 |        BUFFER SORT         |          |       |       |            |          |  Q1,01 | PCWC |            |
|   8 |         PX RECEIVE         |          |     4 |    80 |     5   (0)| 00:00:01 |  Q1,01 | PCWP |            |
|   9 |          PX SEND BROADCAST | :TQ10000 |     4 |    80 |     5   (0)| 00:00:01 |        | S->P | BROADCAST  |
|  10 |           TABLE ACCESS FULL| DEPT     |     4 |    80 |     5   (0)| 00:00:01 |        |      |            |
|  11 |        PX BLOCK ITERATOR   |          |    14 |   518 |     3   (0)| 00:00:01 |  Q1,01 | PCWC |            |
|  12 |         TABLE ACCESS FULL  | EMP      |    14 |   518 |     3   (0)| 00:00:01 |  Q1,01 | PCWP |            |
--------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   6 - access("E"."DEPTNO"="D"."DEPTNO")

24 rows selected.

  • 그림 7_3을 보면, 쿼리 서버 집합 간(P->P) Inter-Operation Parallelism이 발생할 때는 사용자가 지정한 병렬도(=2)의 배수(4개)만큼
    서버 프로세스가 필요한것을 알 수 있다.
    또한 테이블 큐(:TQ10001)에는 병렬도의 제곱(2*2=4)만큼 파이프 라인이 필요하다는 사실도 알 수 있다.
    참고로 그림 7_2를 보면, 병렬도가 4이므로 8(4*2)개 서버 프로세스를 위해 16(4*4)개의 파이프 라인이 형성됨.

2) 생산자/소비자 모델

  • 테이블 큐에는 항상 생산자(Producer)와 소비자(Consumer)가 존재함.
  • 처음 DEPT 테이블을 읽어 분배하는 :TQ10000에서는 QC가 생산자, 서버집합 1이 소비자
  • 두번째 테이블 큐 :TQ10001에서는 서버 집합 1이 생산자, 서버집합 2가 소비자
  • 마지막으로, 정렬된 최종 결과집합을 전송하는 :TQ10002에서는 서버집합 2가 생산자, QC가 소비자

3) 병렬 실행계획에서 생상자와 소비자 식별

  • 위의 실행계획을 가지고 설명하면, 생산자는 'PX SEND', 소비자는 'PX RECEIVE'가 표시됨
  • 구간별 설명

1. Id 9~10
- QC가 DEPT 테이블을 읽어 첫 번째 서버집합(Q1, 01)에게 전송

2. Id 5~12
- 첫 번째 서버집합(Q1,01)은 EMP 테이블을 병렬로 읽으면서 앞서 QC에게서 받은 DEPT 테이블과 조인
- 조인에 성공한 레코드는 바로바로 두 번째 서버집합(Q1, 02)에게 전송

3. Id 2~12
- 마지막으로, 두 번째 서버집합(Q1, 02)은 전송받은 레코드를 정렬하고 나서 QC에게 전송

  • 참고로 생산자로부터 소비자로 데이터 재분배가 일어날 때마다 'Name' 컬럼에 테이블 큐(:TQ10000 형태)가 표시됨

4. IN-OUT 오퍼레이션

  • 실행계획에서 'IN-OUT' 지표에 나타난 내용들을 살펴보고자 함
NAMEDESCRIPTION설명
S->PPARALLEL_FROM_SERIAL☞ QC가 읽은 데이터를 테이블 큐를 통해 병렬 서버 프로세스에게 전송
P->SPARALLEL_TO_SERIAL☞ 각 병렬 서버 프로세스가 처리한 데이터틀 QC에게 전송

☞ 병렬 프로세스로부터 QC로 통신이 발생하므로 Inter-Operation Parallelism에 속함

(그러나 S->P는 통신을 하지만 병렬 오퍼레이션이 아니므로 Inter-Operation Parallelism이 아님)

☞ 'PQ Disrib' 항목에 있는 'QC(ORDER)' 의미는 ORDER BY가 사용되어 첫 번째 병렬 프로세스로부터 마지막 병렬 프로세스까지 순서대로 진행함을 의미

(만약 ORDER BY가 없다면 'QC(RAND)'가 나옴)
P->PPARALLEL_FROM_PARALLEL☞ 해당 오퍼레이션을 두 개의 서버집합이 처리함을 의미

☞ 두 개의 서버집합간 통신이 발생하므로 Inter-Operation Parallelism에 속함
PCWPPARALLEL_COMBINE_WITH_PARENT☞ 한 서버집합이 현재 스텝과 그 부모(Parent) 스텝을 모두 처리함을 의미

☞ 병렬 오퍼리에션이긴 하지만 한 서버 집합 내에서는 프로세스 간 통신이 발생하지 않으므로 Intra-Operation Parallelism에 속함.
PCWCPARALLEL_COMBINE_WITH_CHILD☞ 한 서버집합이 현재 스텝과 그 자식(Child) 스텝을 모두 처리함을 의미

☞ 병렬 오퍼리에션이긴 하지만 한 서버 집합 내에서는 프로세스 간 통신이 발생하지 않으므로 Intra-Operation Parallelism에 속함.
  • 참고로 'IN-OUT'에서 값이 없을 때 는 Serial 방식으로 처리됨을 의미

5. 데이터 재분배

NAME설명
RANGE☞ ORDER BY 또는 GROUP BY를 병렬로 처리할 때 사용됨.

☞ 정렬 작업을 맡은 두 번째 서버 집합의 프로세스마다 처리범위를 지정하고 나서, 데이터를 읽는 첫 번째 서버 집합이 두 번째 서버 집합의 정해진 프로세스에게 "정렬된 키 값에 따라" 분배하는 방식

☞ QC는 각 서버 프로세스에게 작업 범위를 할당하고 정렬 작업에는 직접 참여하지 않으며, 정렬이 완료되면 순서대로 결과를 받아서 사용자에게 전송하는 역할만 진행
HASH☞ 조인이나 HASH GROUP BY를 병렬로 처리할 때 사용.
BROADCASE☞ QC 또는 첫 번째 서버 집합에 속한 프로세스들이 각각 읽은 데이터를 두 번째 서버 집합에 속한 "모든" 병렬 프로세스에게 전송하는 방식
KEY☞ 특정 컬럼 기준으로 테이블 또는 인덱스를 파티셔닝할 때 사용하는 분배 방식
ROUND-ROBIN☞ 파티션 키, 정렬 키, 해시 함수 등에 의존하지 않고 반대편 병렬 서버에 무작위로 데이터를 분배하는 방식.

6. Granule

☞ 데이터를 병렬로 처리할 때 일의 최소 단위를 'Granule'이라고 하며, 병ㅕㄹ 서버는 한 번에 하나의 Granule씩만 처리
☞ Granule 개수와 크기는 병렬도와 관계가 있으며, 이는 병렬 서버 사이에 일을 고르게 분배하는데 큰 영향을 줌

1) 블록 기반 Granule(=블록 범위 Granule)

  • 블록 기반 Granule은, 파티션 테이블인지 여부와 상관없이 대부분의 병렬 오퍼레이션에 적용되는 기본 작업 단위
  • 실행계획 상에서는 'PX BLOCK ITERATOR'라고 표시
  • QC는 테이블로부터 읽어야 할 일정 범위의 블록을 Granule로서 각 병렬 서버에게 할당하며, 병렬 서버가 한 Granule에 대한 일을 끝마치면 다른 Granule을 할당함.
  • Granule 크기와 총 개수는 실행 시점에 오브젝트 사이즈와 병렬도에 따라 QC가 동적으로 결정함.

|  11 |        PX BLOCK ITERATOR   |          |    14 |   518 |     3   (0)| 00:00:01 |  Q1,01 | PCWC |            |
|  12 |         TABLE ACCESS FULL  | EMP      |    14 |   518 |     3   (0)| 00:00:01 |  Q1,01 | PCWP |            |

2) 파티션 기반 Granule(=파티션 Granule)

  • 파티션 기반 Granule이 사용될 때, 각 병렬 서버 프로세스는 할당받은 테이블(또는 인덱스) 파티션 전체를 처리할 책임을 진다.
    이 때, 한 파티션을 두 개 프로세스가 함께 처리할 수 없으므로 병렬도는 당연히 파티션 개수 이하로만 지정
  • 실행계획 상에서는 'PX PARTITION RANGE ALL' 또는 'PX PARTITION RANGE ITERATOR'라고 표시
  • 파티션 기반 Granule은 아래와 같은 작업 수행시 사용
Partition-Wise 조인
파티션 인덱스를 병렬로 스캔할 때
파티션 인덱스를 병렬로 갱신할 때
9iR1 이전에서의 병렬 DML
파티션 테이블 또는 파티션 인덱스를 병렬로 생성할 때
  • 파티션간 데이터량의 편차가 심할 경우 오히려 효과적인 분산이 어려우므로 '블록 기반 Granule' 보다 못하므로,
    파티션 기반 Granule은 병렬도보다 파티션 개수가 상당히(병렬도의 3배 이상) 많을 때라야 유용

|   4 |     PX RECEIVE                    |          |    14 |   126 |     3   (0)| 00:00:01 |       |       |  Q1,01 | PCWP |            |
|   5 |      PX SEND PARTITION (KEY)      | :TQ10000 |    14 |   126 |     3   (0)| 00:00:01 |       |       |  Q1,00 | P->P | PART (KEY) |
|   6 |       PX PARTITION RANGE ITERATOR |          |    14 |   126 |     3   (0)| 00:00:01 |       |       |  Q1,00 | PCWC |            |
|   7 |        TABLE ACCESS FULL          | EMP      |    14 |   126 |     3   (0)| 00:00:01 |       |       |  Q1,00 | PCWP |            |

7. 병렬 처리 과정에서 발생하는 대기 이벤트

☞ 병렬 처리 과정에서 자주 발생하는 대기 이벤트 요약

이벤트명클래스설명
PX Deq: Execute ReplyIdle☞ QC가 각 병렬 서버에게 작업을 배분하고서 작업이 완료되기를 기다리는 상태
PX Deq: Execute MsgIdle☞ 병렬 서버가 자신의 임무를 완수하고서 다른 병렬 서버가 일을 마치기를 기다리는 상태.

☞ QC 또는 소비자 병렬 서버에게 데이터 전송을 완료했을 때 나타남.
PX Deq: Table Q NormalIdle☞ 메세지 수신 대기. 메세지 큐에 데이터가 쌓이기를 기다리는 상태.
PX Deq Credit: send blkdOther☞ 메세지 송신 대기.

☞ QC 또는 소비자 병렬 서버에게 전송할 데이터가 있는데 블로킹 된 상태.

☞ 생산자 프로세스가 메세지 큐를 통해 데이터를 전송하려고 하는데 어떤 이유에서건 소비자 프로세스가 버퍼에서 데이터를 빨리 꺼내가지 않을 때 발생.
PX Deq Credit: need bulfferIdle☞ 데이터를 전송하기 전에 상대편 병렬 서버 또는 QC로부터 credit 비트를 얻으려고 대기하는 상태.

☞ 오라클 측의 설명(메타링크 문서번호 271767.1)에 의하면 'PX Deq Credit:send blkd'와 'PX Deq Credit: need bulffer'는 거의 같은 대기 이벤트이고, 내부적인 이유로 전자는 로컬 시스템에서 자주 발생하며, 후자는 RAC 시스템에서 자주 발생함.

1) 대기 이벤트 모니터링


-- 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

  • 작업을 처음 시작하면 QC에는 'PX Deq: Execute Reply'이벤트가 보이며, 가장 먼저 작업을 끝낸 병렬 서버로부터 데이터를 받아 클라이언트에게 전송할때는 'SQL*Net Message from client'로 변경됨
  • 병렬서버에서 'PX Deq: Execution Msg' 메세지는 작업을 다 마친 의미이며, 'direct path read'는 작업이 수행중인 의미임.

2) 대기 이벤트 해소

문서에 대하여