1. 기본 개념









SQL 이 수행할 작업 범위를
여러개의 작은 단위로 나누어
여러 프로세스(쓰레드 - Windows) 가 동시 처리



(1) Query coordinator 와 병렬 서버 프로세스




Qiery coordinator(QC)
  • 병렬 SQL 문을 발생시킨 세션
    1. DOP(Degree Of Parallelism) 과 작업 종류에 따라 1~2개의 병렬서버집합 할당
    2. 서버 풀로부터 필요한 만큼 서버 프로세스 확보, 부족분은 새로 생성
    3. 각 병렬 서버에게 작업 할당
    4. 병렬처리 대상이 아닌 테이블은 QC 가 직접 처리
    5. 각 병렬서버로부터의 산출물 통합
    6. 최종 결과집합을 사용자에게 전송, DML 일 때는 건수를 집계해서 전송
    7. 쿼리 결과 전송 단계의 스칼라 서브쿼리도 QC 가 수행 함



  • 인스턴스 기동 시 오라클은 parallelmin_servers 만큼의 프로세스를 미리 생성 해 두어 부하를 경감시킨다



병렬 서버 프로세스
  • 실제 작업을 수행하는 개별 새션





(2) Intra - Inter Operation parallelism




Intra - Operation parallelism
  • 개별 서버 프로세스가 각각 자신의 작업을 하고 QC 가 최종 머지하는 방식
    • 서버 프로세스의 수가 많을수록 최종 머지 시 QC 에 부하가 걸려 비 효율 요소가 있다



Inter - Opeation parallelism





  • 서버 프로세스를 두 개 조로 나누어 서로 다른 작업을 하는 방식
    • 각 프로세스 간 통신이 발생하는 비 효율 요소가 있다





(3) 테이블 큐


  • Inter - Operaion 시 프로세스 데이터 전송을 위한 통신 채널이 필요하다


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 d.deptno = e.deptno order by e.ename







테이블 큐는
  • 서버 프로세스 간(P-P) 또는 프로세스와 QC 간(P-S) 데이터 전송을 위해 연결 된 파이프라인
  • 테이블 큐 식별자는 각 테이블 큐에 부여 된 이름
  • 테이블 큐는 P-P 시에는 병렬도(DOP) 의 2배수 만큼 필요



생산자/소비자 모델
  • 테이블 큐를 기준으로 각각 생산자와 소비자가 존재
  • 생산자는 데이터를 처리하여 주는 쪽, 소비자는 받아서 처리하는 쪽
  • 각 서버 프로세스 집합은 생산자도 될 수 있고, 소비자도 될 수 있음
  • Select 문장의 최종 소비자는 항상 QC
  • 소비자 역할을 하는 서버집합은 from 절에 테이블 큐를 참조하는 서브 SQL 로 작업 수행 함



병렬 실행계획에서 생산자와 소비자 식별




  • PX SEND/RECEIVE 표시를 통해 분배 과정을 확인할 수 있다
  • TQ 컬럼의 값으로 각 오퍼레이션을 수행하는 서버 프로세스 집합을 알 수 있다
  • Name 컬럼에서 생산자-소비자 간 데이터 전송하는 테이블 큐 명을 확인 할 수 있다
    1. QC 가 DEPT 테이블을 읽어 첫 서버집합 Q1,01 에 전송
    2. 첫 서버집합 Q1,01 은 EMP 테이블을 병렬로 읽으면서 QC 에서 받은 DEPT 테이블과 조인 후 두 번째 집합 Q1,02 에 전송
    3. 두 번째 서버 집합 Q1,02 는 전송 레코드를 정렬 후 QC 에 전송





(4) In - Out 오퍼레이션







  • 테이블 큐를 통한 In-Out 정보를 확인 가능하다.
  • S->P: Parallel from Serial
    **QC 가 읽은 데이터를 테이블 큐를 통해 병렬 프로세스에게 전송

  • P->S: Parallel to Serial
    • 각 병렬 서버 프로세스가 처리한 데이터를 QC 에게 전송
    • 병렬 프로세스로부터 통신이 발생하므로 Inter - Operation 에 속한다(S \-> P 는 직렬이므로 속하지 않는다고 한다)

  • PQ Distrib
    • QC (ORDER) 일 때는 QC 에게 전송할 때 첫 프로세스부터 마지막 프로세스까지 순차 진행(SQL 에 Order by 있을 때)
    • QC (RANDOM) 일 때는 QC 에게 전송할 때 첫 프로세스부터 마지막 프로세스까지 작업 순 진행

  • P-->P: Parallel to Parallel
    • 정렬, 그룹핑 혹은 조인을 위해 동적 파티셔닝할 때 사용
    • 첫 서버 집합이 읽거나 가공 한 데이터를 두 번째 집합에 전송(Inter - Operation)

  • PCWP: Parallel Combined With Parent
    • 한 서버 집합이 현재 단계와 부모 단계 작업을 모두 처리
    • 한 서버 집합이 주문_IDX1 인덱스를 스캔하면서(8-7) 주문 테이블을 엑세스(4-3)
    • 같은 서버 집합 내에서는 프로세스 간 통신이 발생하지 않으므로 Inter - Operation
    • 자식 스텝의 처리 결과를 부모 스텝에서 그대로 사용하는 것

  • PCWC: Parallel Combined With Child
    • 실행계획 상 3번 단계(PCWP 와 엮여 있음)



정리하면
  • S->P, P->S, P->P 는 프로세스 간 통신 발생
  • P->P, P->S 는 병렬, S->P 는 직렬 Operation
  • PCWP, PCWC 는 각 병렬 서버 집합이 여러 단계를 처리할 때 발생하며, 프로세스 간 통신이 발생하지 않음
  • 실행계획 상 S->P 가 나타나면 해당 단계가 병목인지 의심 해 볼 필요 있음





(5) 데이터 재 분배




  • S->P, P->P 방식일 때 발생하며, 5가지 방식이 있음



RANGE
  • Order by, Group by 를 병렬처리 시 사용
  • 두 번 째 서버집합의 프로세스마다 처리 범위를 지정 후 첫 번 째 서버집합이 정렬 키 값에 따라 분배
  • QC 는 각 프로세스에 작업 범위만 할당하고 직접 참여하지는 않음



HASH
  • 조인이나 Hash group by 를 병렬 처리 시 사용
  • 조인 키나 그룹바이 키 값을 해시함수 적용 후 데이터 분매
  • P->P, S->P 방식 가능



BROADCAST
  • QC 혹은 첫 서버집합 프로세스가 각기 데이터를 두 번째 서버집합의 모든 병렬 프로세스에 전송
  • 크기가 매우 작은 테이블이 있을 때 사용
  • P->P, S->P 방식 가능



KEY
  • 특정 컬럼 기준으로 데이터나 인덱스 파티셔닝하는 분배 방식
  • 실행계획 상 PARTITION (KEY) 로 표기
  • Partial Partition-wise 조인, CTAS, 병렬로 글로벌 파티션 인덱스 생성 시 발생



ROUND-ROBIN
  • 파티션 정렬 키, 해시 함수등에 의존하지 않고 반대편 병렬 서버에 무작위 데이터 분배





(6)Granul


  • 데이터 병렬 처리의 최소 단위
  • 병렬서버는 한 번에 하나의 Granul 만 처리
  • 갯수와 크기는 병렬도와 관련 있음
  • 블록 기반 / 파티션 기반 Granul 로 나뉘며, Oracle 이 자체 판단하여 결정



블록 기반 그레뉼
  • 대부분의 오퍼레이션에 적용되는 기본 작업 단위
  • 테이블 파티션 여부, 갯수와 무관하게 병렬도 지정 가능
  • 실행계획에 PX BLOCK ITERATOR 표시
  • QC 는 테이블에서 읽어야 할 일정 범위의 블록을 그레뉼 단위로 각 병렬 서버에 할당
  • 갯수와 크기는 사이즈/병렬도에 따라 QC 가 동적으로 결정
    • 서로 다른 파일의 블록을 각 병렬 서버에 할당하여 경합 회피 시도



파티션 기반 그레뉼
  • 각 병렬 서버 프로세스는 할당받은 파티션 전체를 처리
  • 병렬도는 파티션 개수 이하로만 지정
  • 실행계획에 PX PARTITION RANGE ALL/PX PARTITION RANGE ITERATOR 표시
  • 파티션 기반 그레뉼은 다음과 같은 작업 수행 시 사용
    1. Partition wise join
    2. Partition index 병렬 스캔/갱신
    3. Partition table/index 병렬 생성



파티션 기반 그레뉼의 특징
  • 병렬도가 파티션 개수에 따라 정적이므로 블록 기반처럼 유연하지 못하다
    1. 파티션 간 데이터 편차 심할 때 리소스 낭비가 있다
    2. 파티션 수보다 많은 병렬도를 사용할 수 없다

  • 따라서 병렬도보다 파티션 개수가 많아 편차를 평준화 시킬 수 있을 때 유리하다



(7) 병렬처리 대기 이벤트


  • 병렬서버/QC 간 데이터 전송을 위해 메시지 버퍼를 사용
  • 생산자가 버퍼에 데이터를 넣으면 소비자가 꺼내가는 방식
  • credit 비트: 테이블 큐를 보호 할 목적으로 사용, 상대편 프로세스에게 credit bit를 받아야 데이터 전송 가능



자주 발생하는 이벤트는 아래와 같다


이벤트명클래스설명
PX Deq: Execute ReplyIdleQC 가 병렬서버에 작업 배분 후 완료대기
PX Deq: Execution MsgIdle병렬서버가 자기 작업 완료 후(소비자/QC 에게 전송 후) 타 병렬서버 완료대기
PX Deq: Table Q NormalIdle메시지 큐 수신 대기
PX Deq Credit: send blkdOther메시지 송신 대기, 어떤 이유에서건 소비자가 메시지 버퍼에서 데이터를 꺼내가지 않을 때
PX Deq Credit: need bufferIdle상대편 병렬 프로세스에 credit bit 를 얻으려고 대기
SQL \*Net message from c1ientIdleQC 가 작업을 끝낸 병렬프로세스로부터 데이터 받아 클라이언트 전송 중(추가 Fetch call 대기 중)




대기 이벤트 해소 방법




병렬처리 관련 이벤트는 대부분 Idle 이벤트로 분류되며, 사용자가 할 수 있는 일이 거의 없다.
  • S \-> P 방식을 P \-> P 방식으로 바꾼다
  • SQL 을 튜닝하여 프로세스 간 전송 량을 줄인다
  • Idle 이벤트가 아닌 경우는 개선이 가능 할 수도 있다
    • PX Deq Credit: send blkd 이 많을 경우는 클라이언트의 Fetch call 사이에 많은 간격이 있을 확률
    • 이 경우 Application 사용을 하지 않거나, 병렬쿼리를 사용하지 않는 편이 나을수도 있다







2.병렬 Order by / Group by






병렬 Order by



select /*+ full (고객) parallel(고객 2) */
고객ID, 고객명, 고객등급
from   고객
order by 고객명 ;


Execution Plan
--------------------------------------------------------------------------------
   0      SELECT STATEMENT Optimizer=ALL_ROWS (Cost=3 Card=1000 Bytes=2M)
   1    0   PX COORDINATOR
   2    1     PX SEND (QC (ORDER)) OF 'SYS.:TQ10001' (Cost=3 Card=1000 Bytes=2M) (PARALLEL_TO_SERIAL) (QC (ORDER))
   3    2       SORT (ORDER BY) (Cost=3 Card=1000 Bytes=2M) (PARALLEL_COMBINED_WITH_PARENT)
   4    3         PX RECEIVE (Cost=2 Card=1000 Bytes=2M) (PARALLEL_COMBINED_WITH_PARENT)
   5    4           PX SEND (RANGE) OF 'SYS.:TQ10000' (Cost=2 Card=1000 Bytes=2M) (PARALLEL_TO_PARALLEL) (RANGE)
   6    5             PX BLOCK (ITERATOR) (Cost=2 Card=1000 Bytes=2M) (PARALLEL_COMBINED_WITH_CHILD)
   7    6               TABLE ACCESS (FULL) OF '고객' (TABLE) (Cost=2 Card=1000 Bytes=2M) (PARALLEL_COMBINED_WITH_PARENT)




  • Order by 수행 과정은 생략한다
  • Order by 를 병렬로 수행하려면 테이블 큐를 통한 재 분배 필요

  • 아래 쿼리로 수행 중인 세션들의 통계 확인 가능하며


se1ect tq_id, server_type, process, num_rows, bytes, waits
from v$pq_tqstat
order by
dfo number, tq_id, decde(substr(server_type, 1, 4), 'Rang', 1, 'Prod', 2, 'Cons', 3), process
;




  • 이는 아래 그림과 같이 표현 가능






  • 이 쿼리를 이용해 테이블 큐를 통한 전송량 편차가 크지 않은지 확인 가능하다





병렬 Group by




  • 병렬 Group by 시 order by 구문 여부에 따라 hash group by / sort group by 플랜으로 나뉜다


select /*+ full(고객) parallel (고객 2) */
고객명, count(*) 
from   고객
group by 고객명 
;

Execution Plan
--------------------------------------------------------------------------------
   0      SELECT STATEMENT Optimizer=ALL_ROWS (Cost=3 Card=1000 Bytes=2M)
   1    0   PX COORDINATOR
   2    1     PX SEND (QC (RANDOM)) OF 'SYS.:TQ10001' (Cost=3 Card=1000 Bytes=2M) (PARALLEL_TO_SERIAL) (QC (RANDOM))
   3    2       HASH (GROUP BY) (Cost=3 Card=1000 Bytes=2M) (PARALLEL_COMBINED_WITH_PARENT)
   4    3         PX RECEIVE (Cost=3 Card=1000 Bytes=2M) (PARALLEL_COMBINED_WITH_PARENT)
   5    4           PX SEND (HASH) OF 'SYS.:TQ10000' (Cost=3 Card=1000 Bytes=2M) (PARALLEL_TO_PARALLEL) (HASH)
   6    5             HASH (GROUP BY) (Cost=3 Card=1000 Bytes=2M) (PARALLEL_COMBINED_WITH_PARENT)
   7    6               PX BLOCK (ITERATOR) (Cost=2 Card=1000 Bytes=2M) (PARALLEL_COMBINED_WITH_CHILD)
   8    7                 TABLE ACCESS (FULL) OF '고객' (TABLE) (Cost=2 Card=1000 Bytes=2M) (PARALLEL_COMBINED_WITH_PARENT)


select /*+ full(고객) parallel (고객 2) */
고객명, count(*) 
from   고객
group by 고객명 
order by 고객명
;
Execution Plan
--------------------------------------------------------------------------------
   0      SELECT STATEMENT Optimizer=ALL_ROWS (Cost=3 Card=1000 Bytes=2M)
   1    0   PX COORDINATOR
   2    1     PX SEND (QC (ORDER)) OF 'SYS.:TQ10001' (Cost=3 Card=1000 Bytes=2M) (PARALLEL_TO_SERIAL) (QC (ORDER))
   3    2       SORT (GROUP BY) (Cost=3 Card=1000 Bytes=2M) (PARALLEL_COMBINED_WITH_PARENT)
   4    3         PX RECEIVE (Cost=3 Card=1000 Bytes=2M) (PARALLEL_COMBINED_WITH_PARENT)
   5    4           PX SEND (RANGE) OF 'SYS.:TQ10000' (Cost=3 Card=1000 Bytes=2M) (PARALLEL_TO_PARALLEL) (RANGE)
   6    5             HASH (GROUP BY) (Cost=3 Card=1000 Bytes=2M) (PARALLEL_COMBINED_WITH_PARENT)
   7    6               PX BLOCK (ITERATOR) (Cost=2 Card=1000 Bytes=2M) (PARALLEL_COMBINED_WITH_CHILD)
   8    7                 TABLE ACCESS (FULL) OF '고객' (TABLE) (Cost=2 Card=1000 Bytes=2M) (PARALLEL_COMBINED_WITH_PARENT)





  • hash/sort group by 는 데이터 분배 방식 외에는 처리 원리는 동일하다
    • group by 키 순서에 따라 분배하거나, hash 키에 따라 분배하거나
    • QC 에게 전송할 때도 값 순서대로 전송하거나, 처리가 끝난대로 랜덤하게 전송

  • 병렬 Group by 도 Order by 와 마찬가지로 두 집합이 한쪽은 분배, 한쪽은 집계한다





Group by 가 두 번 나타나는 실행 과정
  • 아래와 같이 Group by 단계가 플랜 상에 두 번 나타날 때가 있다


select /*+ full (고객) parallel (고객 2) */
고객등급, count(*)
from 고객
group by 고객등급
;

Execution Plan
--------------------------------------------------------------------------------
   0      SELECT STATEMENT Optimizer=ALL_ROWS (Cost=3 Card=1000 Bytes=13K)
   1    0   PX COORDINATOR
   2    1     PX SEND (QC (RANDOM)) OF 'SYS.:TQ10001' (Cost=3 Card=1000 Bytes=13K) (PARALLEL_TO_SERIAL) (QC (RANDOM))
   3    2       HASH (GROUP BY) (Cost=3 Card=1000 Bytes=13K) (PARALLEL_COMBINED_WITH_PARENT)
   4    3         PX RECEIVE (Cost=3 Card=1000 Bytes=13K) (PARALLEL_COMBINED_WITH_PARENT)
   5    4           PX SEND (HASH) OF 'SYS.:TQ10000' (Cost=3 Card=1000 Bytes=13K) (PARALLEL_TO_PARALLEL) (HASH)
   6    5             HASH (GROUP BY) (Cost=3 Card=1000 Bytes=13K) (PARALLEL_COMBINED_WITH_PARENT)
   7    6               PX BLOCK (ITERATOR) (Cost=2 Card=1000 Bytes=13K) (PARALLEL_COMBINED_WITH_CHILD)
   8    7                 TABLE ACCESS (FULL) OF '고객' (TABLE) (Cost=2 Card=1000 Bytes=13K) (PARALLEL_COMBINED_WITH_PARENT)





  • 이 경우는 데이터 선택도 및 카디널리티와 연관이 있다


SQL> select column_name ,
       num_distinct ,
       num_nulls ,
       1/num_distinct selectivity ,
       round(1/num_distinct * t.num_rows, 2) cardinality
from   user_tables t ,
       user_tab_columns c 
where  t.table_name = '고객'
and    c.table_name = t. table_name
order by column_id;

COLUMN_NAME                    NUM_DISTINC NUM_NULLS   SELECTIVITY CARDINALITY
------------------------------ ----------- ----------- ----------- -----------
고객ID                                1000           0       0.001           1
고객명                                1000           0       0.001           1
고객등급                                10           0         0.1         100
가입일                                1000           0       0.001           1

4 rows selected.


  • 고객명의 선택도는 낮고 고객등급의 선택도는 높다
  • 고객 등급으로 group by 시 원래 데이터 집합보다 많이 줄어든다
  • 첫 서버 집합이 그룹 바이 먼저 수행하고 두 번 째 집합에 전송 시 통신량 경감 효과
    1. 첫 서버 집합은 QC 로부터 데이터를 받아 자체 그룹바이(PCWP)
    2. 그룹바이 결과값을 해시함수 적용 해 두 번 째 서버 집합에 분배(P->P)
    3. 두 번 째 그룹바이 집합은 배타적 데이터 셋으로 다시 그룹바이 수행 후 QC 전송(P->S)
  • 그룹바이를 두 번 하게 되지만 테이블 큐를 통한 전송 부하를 감소시킬 수 있다






  • 11G: gby_pushdown, no_gby_pushdown 힌트로 group by 방식 조절 가능 함







3. 병렬 조인




  • 서로 독립적으로 조인을 수행하도록 데이터를 분배하는 것이 핵심
  • 분배가 완료되면 각기 할당받은 범위에서 조인 완료
  • 크게 두 가지 방식이 있다
    1. 파티션 방식: 파티션 짝 끼리 조인
    2. Broadcast 방식: 한쪽 테이블을 Broadcast 방식으로 분배 후 조인 수행



  • 파티션 방식 조인은 테이블의 파티션 상태에 따라 다음과 같이 나뉜다.
    1. 둘 다 같은 기준 파티셔닝 된 경우
    2. 둘 다 파티셔닝 되었지만 파티션 기준이 서로 다름/둘 중 하나만 파티셔닝
    3. 둘 다 파티셔닝 되지 않음





(1) 파티션 조인 - 둘 다 같은 기준으로 파티셔닝





  • Full Partition Wise 조인 이라고 함
  • 이미 상호 배타적인 파티션 집합 짝이 형성되어 있으므로 각 서버 프로세스가 독립적으로 수행



특징은 다음과 같다
  1. 하나의 서버 집합만 필요
  2. 파티션 기반 그레뉼이므로 프로세스 개수는 파티션 개수 이하
  3. 파티션 방식(Range/Hash/List) 및 조인 방식은 어떤 것이든 선택 가능하다





(2) 파티션 조인 - 파티션 기준 상이/둘 중 하나만 파티셔닝





  • Partial Partition Wise 조인 이라고 함
  • 한쪽을 다른쪽에 맞추어 동적 파티셔닝 후 각 파티션을 독립적으로 병력 조인
  • 동적 파티션을 위해 데이터 재 분배 필요(서버 집합이 두 개 필요)
  • 플랜에 PARTITION (KEY) 라고 표시되는 쪽이 동적 파티셔닝 되는 쪽





(3) 파티션 조인 - 둘 다 파티셔닝 되지 않음


  • 오라클은 다음 두 가지 방법을 수행한다
    1. 양 테이블을 동적으로 파티션 후 Full Partition wise join
    2. 한쪽 테이블을 Broadcast 후 조인



양 테이블을 동적 파티셔닝 하는 경우에 대해






  1. 첫 서버 집합이 1번 테이블(dept) 를 읽어 두 번째 서버집합 전송
  2. 첫 서버 집합이 2번 테이블(emp) 를 읽어 두 번째 서버 집합에 전송
  3. 두 번째 서버 집합은 조인 후 결과 반환



특징은
  1. 조인 수행 전 메모리/템프 공간을 많이 사용
  2. 양쪽 테이블 모두 전체범위 처리 필요
  3. 조인 컬럼 데이터 분포가 균일하지 않을 때는 병렬처리 효과 감소
    1. 이 문제는 Partition wise 조인에서도 발생 가능하나 이는 파티션 설계 미스다



아래와 같은 때 사용에 유리하다
  • 두 테이블 모두 대용량이며
  • 조인 컬럼 데이터 분포 균일





(4) 파티션 조인 - Broadcast





  • 조인 컬럼에 대해 어느 한 쪽도 파티셔닝 되지 않은 상황
  • 두 테이블 중 작은 쪽을 반대편 모든 프로세스에 중복해서 배포 후 조인 수행



특징은
  • 양쪽 테이블 모두 파티션이 없을 때,Broadcast 테이블이 작을 때 유용
    • 이 경우 동적 파티셔닝보다 메모리 및 Temp 사용량이 적기 때문
  • Broadcast 되는 테이블은 Serial Scan 으로 처리(S->P) 될 때도 있다
  • 조인 방식은 어느쪽이든 가능하다
  • Broadcast 되지 않는 조인 테이블(INNER TABLE)은 부분범위 처리가 가능하다







4. PQ Distribute 힌트




(1) 용도


  • 병렬 조인 시 데이터 분배 방식을 사용자가 직접 지정해야 할 상황
    1. 옵티마이저가 비 효율적 동적 재 분할 할 때
    2. 기존 파티션 키 외 다른 값으로 동적 재 분할 하고자 할 때
    3. 통계가 부정확한 상황에서 실행계획 고정시킬 때

  • 조인 전 분배 작업에 관여하는 힌트이며, 조인 방식을 결정하는 힌트는 아님





(2) 구문



/*+ PQ_DISTRIBUTE(INNER_TABLE, OUTER_TABLE_분배방식, INNER_TABLE 분배방식) */


  • 조인 순서를 고정시키는 것이 중요하므로, LEADING 이나 ORDERED 등의 힌트를 함께 사용하는 것이 좋다





H3.(3) 분배방식 지정

  1. PQ_DISTRIBUTE(INNER, NONE, NONE)
    • Full Partition Wise 조인
    • 양쪽 모두 조인 컬럼에 같은 기준으로 파티셔닝 되어 있을 때만 작동



  2. PQ_DISTRIBUTE(INNER, PARTITION, NONE)
    • Partial Partition Wise 조인
    • Outer 테이블을 Inner 테이블 기준에 따라 파티션
    • Inner 테이블이 조인 키 컬럼에 대해 파티셔닝 되어 있을 때만 작동

  3. PQ_DISTRIBUTE(INNER, NONE, PARTITION)
    • Partial Partition Wise 조인
    • Inner 테이블은 Outer 테이블 기준에 따라 파티션
    • Outer 테이블이 조인 키 컬럼에 대해 파티셔닝 되어 있을 때만 작동



  4. PQ_DISTRIBUTE(INNER, HASH, HASH)
    • 조인 키 컬럼을로 해시 함수를 적용하여 동적 파티션



  5. PQ_DISTRIBUTE(INNER, BROADCAST, NONE)
    • OUTER TABLE 을 BROADCAST

  6. PQ_DISTRIBUTE(INNER, NONE, BROADCAST)
    • INNER TABLE 을 BROADCAST





(4) 튜닝 사례


  • 자세한 내용은 책 참조





블룸 필터 알고리즘을 활용 한 프로세스 간 통신량 최소화


  • 원리는 6장에서 임갑중님에 의해 자세히 설명되었다
  • 아래와 같은 쿼리 수행 시
    • 지역이 시카고 인 deptno 에 해시 함수 적용하여 비트들을 1로 설정
    • 병렬 서버 집합이 emp 테이블을 읽어 소비자 집합에 전송 시 먼저 블룸필터 탐색 후
    • 비트값이 1인 deptno 일 때만 전송하고 나머지는 버린다


select /* + full(d) full(e) parallel(d 2) parallel(e 2) */
d.deptno, d.dname, e.ename
from dept d, emp e
where e.deptno = d.deptno
and d.loc = 'CHICAGO'




  • \_bloom_filter_enabled 를 통해 제어 가능하다
  • px_join_filter / no_px_join_filter 힌트로도 제어 가능하다







5 병렬 처리 기타 상식






병렬처리로 full scan 시 Direct path read를 사용 함
  • 작은 테이블을 병렬처리 시 속도가 더 안나올 수 도 있다
    • Direct read 보다는 in memory read 가 더 빠르기 때문
    • Direct read 시 Checkpoint 를 우선 수행해야 하기 때문



병렬 enable
  • 병렬 처리에 대한 enable/disable 은 아래처럼 제어 가능하다
    • alter session enable/disable parallel query ; (default enable)
    • alter session enable/disable parallel dml ; (default disable)
    • alter session enable/disable parallel ddl ; (default enable)

  • 병렬 DML 시 해당 테이블에 Exclusive 모드 락이 설정된다.



병렬 인덱스 스캔
  • Index fast full 스캔이 아닌 한 Non-partition 인덱스의 병렬 스캔은 불가능하다
  • Partition index 일 때는 가능하다
    • 다만 병렬도는 파티션 개수 이하로만 유효하다



병렬 NL 조인
  1. Outer 테이블을 풀로 읽어 Inner 를 NL 조인할 수 있으며
  2. 파티션 인덱스로 드라이빙하여 NL 조인도 가능하다
    1. 이 때는 Inner/Outer 테이블 및 두 번 째 인덱스의 파티션과는 무관하다


select
/*+ ordered use_nl(d) full(e) parallel(e 3) */
/*+ ordered use_nl(d) index(e emp_sal_idx) parallel_index(e emp_sal_idx 3) */
*
from emp e, dept d
where d.deptno = e.deptno
and e.sal >= 1000 ;




병렬 쿼리와 스칼라 서브쿼리
  • 일반적으로 병렬 프로세스에서 받은 집합을 QC 가 클라이언트에 전송하면서 수행
  • 쿼리 블록에 Order by 가 있을 경우 병렬 서버 프로세스가 정렬 처리를 하는 동시에 스칼라 서브쿼리 수행
    • 병렬 쿼리는 대부분 Full scan 을 하는데 스칼라 서브쿼리를 사용하면 큰 비효율
    • 가급적 조인문으로 변경해야 함



병렬 쿼리와 함수
  • parallel_enable 키워드 없이도 병렬 수행 가능
  • parallel_enable 의 역할은?
    • 세션 변수를 사용 시 병렬 수행 여부에 따라 결과가 달라질 수 있음
    • 이 때 함수는 강제로 QC 가 Serial 하게 수행 함
    • parallel_enable 사용 시 세션 변수를 사용함에도 병렬처리를 할 수 있도록 함



병렬 쿼리와 rownum
  • rownum 사용 시 제약이 따름(QC 가 Order by 를 처리하는 등..)



기타
  • 책 참조