1. 기본 개념
SQL 이 수행할 작업 범위를
여러개의 작은 단위로 나누어
여러 프로세스(쓰레드 - Windows) 가 동시 처리
(1) Query coordinator 와 병렬 서버 프로세스
Qiery coordinator(QC)
- 병렬 SQL 문을 발생시킨 세션
- DOP(Degree Of Parallelism) 과 작업 종류에 따라 1~2개의 병렬서버집합 할당
- 서버 풀로부터 필요한 만큼 서버 프로세스 확보, 부족분은 새로 생성
- 각 병렬 서버에게 작업 할당
- 병렬처리 대상이 아닌 테이블은 QC 가 직접 처리
- 각 병렬서버로부터의 산출물 통합
- 최종 결과집합을 사용자에게 전송, DML 일 때는 건수를 집계해서 전송
- 쿼리 결과 전송 단계의 스칼라 서브쿼리도 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 컬럼에서 생산자-소비자 간 데이터 전송하는 테이블 큐 명을 확인 할 수 있다
- QC 가 DEPT 테이블을 읽어 첫 서버집합 Q1,01 에 전송
- 첫 서버집합 Q1,01 은 EMP 테이블을 병렬로 읽으면서 QC 에서 받은 DEPT 테이블과 조인 후 두 번째 집합 Q1,02 에 전송
- 두 번째 서버 집합 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 표시
- 파티션 기반 그레뉼은 다음과 같은 작업 수행 시 사용
- Partition wise join
- Partition index 병렬 스캔/갱신
- Partition table/index 병렬 생성
파티션 기반 그레뉼의 특징
- 병렬도가 파티션 개수에 따라 정적이므로 블록 기반처럼 유연하지 못하다
- 파티션 간 데이터 편차 심할 때 리소스 낭비가 있다
- 파티션 수보다 많은 병렬도를 사용할 수 없다
- 따라서 병렬도보다 파티션 개수가 많아 편차를 평준화 시킬 수 있을 때 유리하다
(7) 병렬처리 대기 이벤트
- 병렬서버/QC 간 데이터 전송을 위해 메시지 버퍼를 사용
- 생산자가 버퍼에 데이터를 넣으면 소비자가 꺼내가는 방식
- credit 비트: 테이블 큐를 보호 할 목적으로 사용, 상대편 프로세스에게 credit bit를 받아야 데이터 전송 가능
자주 발생하는 이벤트는 아래와 같다
이벤트명 | 클래스 | 설명 |
---|
PX Deq: Execute Reply | Idle | QC 가 병렬서버에 작업 배분 후 완료대기 |
PX Deq: Execution Msg | Idle | 병렬서버가 자기 작업 완료 후(소비자/QC 에게 전송 후) 타 병렬서버 완료대기 |
PX Deq: Table Q Normal | Idle | 메시지 큐 수신 대기 |
PX Deq Credit: send blkd | Other | 메시지 송신 대기, 어떤 이유에서건 소비자가 메시지 버퍼에서 데이터를 꺼내가지 않을 때 |
PX Deq Credit: need buffer | Idle | 상대편 병렬 프로세스에 credit bit 를 얻으려고 대기 |
SQL \*Net message from c1ient | Idle | QC 가 작업을 끝낸 병렬프로세스로부터 데이터 받아 클라이언트 전송 중(추가 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 시 원래 데이터 집합보다 많이 줄어든다
- 첫 서버 집합이 그룹 바이 먼저 수행하고 두 번 째 집합에 전송 시 통신량 경감 효과
- 첫 서버 집합은 QC 로부터 데이터를 받아 자체 그룹바이(PCWP)
- 그룹바이 결과값을 해시함수 적용 해 두 번 째 서버 집합에 분배(P->P)
- 두 번 째 그룹바이 집합은 배타적 데이터 셋으로 다시 그룹바이 수행 후 QC 전송(P->S)
- 그룹바이를 두 번 하게 되지만 테이블 큐를 통한 전송 부하를 감소시킬 수 있다
- 11G: gby_pushdown, no_gby_pushdown 힌트로 group by 방식 조절 가능 함
3. 병렬 조인
- 서로 독립적으로 조인을 수행하도록 데이터를 분배하는 것이 핵심
- 분배가 완료되면 각기 할당받은 범위에서 조인 완료
- 크게 두 가지 방식이 있다
- 파티션 방식: 파티션 짝 끼리 조인
- Broadcast 방식: 한쪽 테이블을 Broadcast 방식으로 분배 후 조인 수행
- 파티션 방식 조인은 테이블의 파티션 상태에 따라 다음과 같이 나뉜다.
- 둘 다 같은 기준 파티셔닝 된 경우
- 둘 다 파티셔닝 되었지만 파티션 기준이 서로 다름/둘 중 하나만 파티셔닝
- 둘 다 파티셔닝 되지 않음
(1) 파티션 조인 - 둘 다 같은 기준으로 파티셔닝
- Full Partition Wise 조인 이라고 함
- 이미 상호 배타적인 파티션 집합 짝이 형성되어 있으므로 각 서버 프로세스가 독립적으로 수행
특징은 다음과 같다
- 하나의 서버 집합만 필요
- 파티션 기반 그레뉼이므로 프로세스 개수는 파티션 개수 이하
- 파티션 방식(Range/Hash/List) 및 조인 방식은 어떤 것이든 선택 가능하다
(2) 파티션 조인 - 파티션 기준 상이/둘 중 하나만 파티셔닝
- Partial Partition Wise 조인 이라고 함
- 한쪽을 다른쪽에 맞추어 동적 파티셔닝 후 각 파티션을 독립적으로 병력 조인
- 동적 파티션을 위해 데이터 재 분배 필요(서버 집합이 두 개 필요)
- 플랜에 PARTITION (KEY) 라고 표시되는 쪽이 동적 파티셔닝 되는 쪽
(3) 파티션 조인 - 둘 다 파티셔닝 되지 않음
- 오라클은 다음 두 가지 방법을 수행한다
- 양 테이블을 동적으로 파티션 후 Full Partition wise join
- 한쪽 테이블을 Broadcast 후 조인
양 테이블을 동적 파티셔닝 하는 경우에 대해
- 첫 서버 집합이 1번 테이블(dept) 를 읽어 두 번째 서버집합 전송
- 첫 서버 집합이 2번 테이블(emp) 를 읽어 두 번째 서버 집합에 전송
- 두 번째 서버 집합은 조인 후 결과 반환
특징은
- 조인 수행 전 메모리/템프 공간을 많이 사용
- 양쪽 테이블 모두 전체범위 처리 필요
- 조인 컬럼 데이터 분포가 균일하지 않을 때는 병렬처리 효과 감소
- 이 문제는 Partition wise 조인에서도 발생 가능하나 이는 파티션 설계 미스다
아래와 같은 때 사용에 유리하다
- 두 테이블 모두 대용량이며
- 조인 컬럼 데이터 분포 균일
(4) 파티션 조인 - Broadcast
- 조인 컬럼에 대해 어느 한 쪽도 파티셔닝 되지 않은 상황
- 두 테이블 중 작은 쪽을 반대편 모든 프로세스에 중복해서 배포 후 조인 수행
특징은
- 양쪽 테이블 모두 파티션이 없을 때,Broadcast 테이블이 작을 때 유용
- 이 경우 동적 파티셔닝보다 메모리 및 Temp 사용량이 적기 때문
- Broadcast 되는 테이블은 Serial Scan 으로 처리(S->P) 될 때도 있다
- 조인 방식은 어느쪽이든 가능하다
- Broadcast 되지 않는 조인 테이블(INNER TABLE)은 부분범위 처리가 가능하다
4. PQ Distribute 힌트
(1) 용도
- 병렬 조인 시 데이터 분배 방식을 사용자가 직접 지정해야 할 상황
- 옵티마이저가 비 효율적 동적 재 분할 할 때
- 기존 파티션 키 외 다른 값으로 동적 재 분할 하고자 할 때
- 통계가 부정확한 상황에서 실행계획 고정시킬 때
- 조인 전 분배 작업에 관여하는 힌트이며, 조인 방식을 결정하는 힌트는 아님
(2) 구문
/*+ PQ_DISTRIBUTE(INNER_TABLE, OUTER_TABLE_분배방식, INNER_TABLE 분배방식) */
- 조인 순서를 고정시키는 것이 중요하므로, LEADING 이나 ORDERED 등의 힌트를 함께 사용하는 것이 좋다
H3.(3) 분배방식 지정
- PQ_DISTRIBUTE(INNER, NONE, NONE)
- Full Partition Wise 조인
- 양쪽 모두 조인 컬럼에 같은 기준으로 파티셔닝 되어 있을 때만 작동
- PQ_DISTRIBUTE(INNER, PARTITION, NONE)
- Partial Partition Wise 조인
- Outer 테이블을 Inner 테이블 기준에 따라 파티션
- Inner 테이블이 조인 키 컬럼에 대해 파티셔닝 되어 있을 때만 작동
- PQ_DISTRIBUTE(INNER, NONE, PARTITION)
- Partial Partition Wise 조인
- Inner 테이블은 Outer 테이블 기준에 따라 파티션
- Outer 테이블이 조인 키 컬럼에 대해 파티셔닝 되어 있을 때만 작동
- PQ_DISTRIBUTE(INNER, HASH, HASH)
- 조인 키 컬럼을로 해시 함수를 적용하여 동적 파티션
- PQ_DISTRIBUTE(INNER, BROADCAST, NONE)
- PQ_DISTRIBUTE(INNER, NONE, 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 조인
- Outer 테이블을 풀로 읽어 Inner 를 NL 조인할 수 있으며
- 파티션 인덱스로 드라이빙하여 NL 조인도 가능하다
- 이 때는 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 를 처리하는 등..)
기타