상세 컨텐츠

본문 제목

2024년 2월 28일

오라클 퍼포먼스 튜닝

by 병아리 엔지니어 2024. 2. 28. 16:49

본문

 

1교시

 

★ 파티션은 레퍼런스를 꼭 만들어놓도록 하자.

 

★ 숙제 !!!!!!!!!!!!!!!!!!!!!!

commit 발생시 어떤 일이 일어나는지 / select 문의 처리과정 / DML 문의 처리과정 종이에 써서 제출하기

 

★ 병렬 처리 parallel query

- SQL 문이 수행해야 할 작업 범위를 여러 개의 작은 단위로 나누어

  여러 개의 (서버) 프로세스가 동시에 처리하도록 하는 작업을 의미한다.

  (혼자 할 일을 여럿이서 하기 때문에 처리속도가 빨라진다)

 

샘플 테이블 생성하기

HR@ora11g> drop table hr.emp purge;

 

HR@ora11g>

create table hr.emp nologging as
select rownum as employee_id, last_name, first_name, hire_date, job_id, salary, manager_id, department_id
from hr.employees e, (select level as id from dual connect by level <= 1000);

Table created.

 

HR@ora11g>
exec dbms_stats.gather_table_stats('HR', 'EMP', degree => 2)

PL/SQL procedure successfully completed.

degree = 병렬 프로세스 개수, CPU의 2배수까지 쓸 수 있다. (주로 짝수를 쓴다)

degree 2 = 프로세스 2개 = 서버프로세스 1개가 혼자 해야 하는 작업을 둘이 나눠서 한다 = 처리 속도가 2배로 빠르다.

(단 여기서 버추얼로 병렬처리 테스트를 하면 오히려 더 느려진다... 그래도 현장에서는 다르다고 하시니

너무 실망하지 말자.)

 

통계 정보 확인하기

HR@ora11g> select num_rows, blocks, avg_row_len, logging from user_tables where table_name = 'EMP';

 

※ 데일리 체크시에는 로깅으로 되어있어야 하는데 로깅으로 되어있는 것들 찾아서 바꿔주는 작업도 꼭 해주자.

(대량의 데이터 부어넣는 작업 시에는 꼭 노로깅으로 바꾸고 나서 해주기)

 

HR@ora11g> alter table hr.emp logging;
Table altered.

 

HR@ora11g> select num_rows, blocks, avg_row_len, logging from user_tables where table_name = 'EMP';

 

arraysize 확인하기

HR@ora11g> show arraysize
arraysize 15 : fetch I/O call 이 너무 많이 발생할 수 있다.

 

arraysize 1000 으로 조정하기

HR@ora11g> set arraysize 1000

 

확인

HR@ora11g> show arraysize
arraysize 1000

 

HR@ora11g> alter session set statistics_level = all;
Session altered.

 

# 직렬로 풀 테이블 스캔 serial full table scan

 

HR@ora11g> select /*+ full(e) */ count(*) from emp e;

 

HR@ora11g> select * from table(dbms_xplan.display_cursor(null, null, 'allstats last'));

I/O 754건 발생 + 0.01초 걸림

 

그럼 이제 병렬처리를 한번 유도해보자.

 

# 병렬로 풀 테이블 스캔 parallel full table scan (direct path read)

 

병렬처리 유도 : 힌트를 가지고 프로세스 2개로 e 테이블을 풀 테이블 스캔하도록 함

(DBC 를 건드리지 않고, 프로세스 2개가 디스크에서 바로 커서로 데이터를 읽어들인다.)

HR@ora11g> select /*+ full(e) parallel(e 2) */ count(*) from emp e;

 

병렬처리한 SQL 문의 실행계획을 볼 때는 뒤에 꼭 parallel 옵션을 표시해주어야 한다.

select * from table(dbms_xplan.display_cursor(null, null, 'allstats last parallel'));

I/O 5 건 발생 + 걸린 시간 0.14 초 (뭐야... 아까 0.01 초였는데 오히려 더 늘어났어...)

 

그럼 본격적인 병렬처리에 대해 2교시에서 배워보자.


2교시

 

HR@ora11g> select /*+ full(e) parallel(e 2) */ count(*) from emp e;

 

select * from table(dbms_xplan.display_cursor(null, null, 'allstats last parallel'));

1행의 SORT AGGREGATE 는 그룹함수를 썼다는 뜻

3행의 QC 는 Query Coordinator 의 약자

 

★ Query Coordinator (QC)

- 병렬 SQL 문이 발생한 세션

- 작업을 지시하고 일이 잘 진행되는지 관리, 감독하는 역할을 한다. (작업반장)

 

★ 병렬 서버 프로세스

- 실제 작업을 수행하는 개별 세션

- 병렬 서버 = 병렬 프로세스 = 병렬 슬레이브

 

★ 병렬 서버 풀 (parallel execution server pool)

- 병렬처리시 서버 풀에 있는 프로세스부터 사용 (미리 만들어놓은 프로세스부터 가져다 쓴다)

- 부족하면 추가로 생성한다.

- 생성할 수 있는 최대 병렬 서버 개수는?

  parallel_max_servers 파라미터로 확인 가능 

  (show parameter parallel_max_servers : sys 창에서 확인해야 함, 최대 80개까지 쓸 수 있다고 나온다)

 

- 생성할 수 있는 최소 병렬 서버 개수는?

  parallel_min_servers 로 확인 가능 (show parameter parallel_min_servers)

 

- 병렬 처리가 발생하지 않더라도 parallel_min_servers 파라미터에 지정된 개수만큼 병렬프로세스를 유지한다.

  이유는? 병렬처리시 서버프로세스를 띄우는 데 드는 부하를 줄이기 위해서

 

★ 병렬서버집합 (server set) 할당

- 병렬도 (DOP = Degree Of Parallelism) 와 수행하는 오퍼레이션의 종류에 따라

  한 개 또는 두 개의 병렬 서버 집합을 할당한다. (뒤에 다시 설명해주신다고 하심)

- 서버 풀 (parallel execution server pool) 로부터 필요한 만큼 (미리 만들어놓은) 서버 프로세스를 확보한다.

- 부족하면 새로 생성한다.

 

★ IN-OUT 오퍼레이션

아래 IN-OUT 컬럼을 보면: 공백이 있는 부분도 있고 뭔가 써있는 부분도 있는데

1. 공백이 있는 부분: 직렬 작업, 즉 serial 작업이 일어났다는 뜻

2. 뭔가 내용이 있는 부분:

- P → S : Parallel to Serial (3행)

  (각 병렬 서버 프로세스가 처리한 데이터를 코디네이터 QC 에게 전송할 때 serial 하게 전송한다는 뜻)

  3행을 보면 RANDOM, PQ Distrib 은 QC (RAND) 라고 나오는데 이건 Order by 되지 않고 무작위로 전송되었다는 뜻

  즉, RANDOM 은 정렬이 일어나지 않았을 때 표시되며, 병렬 프로세스들이 무순위로 QC 에게 데이터를 전송한다.

- PCWP : Parallel Combined With Parent (4, 5, 6행) 

  한 서버 집합이 현재 스텝과 그 부모 스텝을 모두 처리하는 기능

  (현재도 처리하고 바로 앞도 처리)

- PCWC : Parallel Combined With Child

  한 서버 집합이 현재 스텝과 그 자식 스텝을 모두 처리하는 기능

- S → P : Parallel From Serial

  코디네이터 (QC) 가 읽은 데이터를, 테이블 큐를 통해 병렬 서버프로세스에게 전달하는 것

- P → P : Parallel to Parallel

  데이터 정렬, 또는 데이터를 그룹핑하거나 조인을 위해 동적으로 파티셔닝할 때 사용

  첫번째 병렬 서버 집합이 읽거나 가공한 데이터를 두번째 병렬 서버 집합에 전송

 

order by 절을 쓴 SQL 문을 한번 수행해보자.

 

HR@ora11g>

select /*+ full(e) parallel(e 2) */ * from emp e
order by last_name;

107000 rows selected.

 

HR@ora11g> select * from table(dbms_xplan.display_cursor(null, null, 'allstats last parallel'));

 

HR@ora11g>

select tq_id, server_type, process, num_rows, bytes, waits
from v$pq_tqstat
order by tq_id, decode(substr(server_type, 1, 4), 'RANG', 1, 'Prod', 2, 'Cons', 3), process;

 

(Producer : 생산자 = 작업을 생성해오는 쪽 = 데이터 추출팀 = 데이터를 추출해서 버퍼에 저장

 Consumer : 소비자 = 작업을 처리 = 버퍼에 있는 데이터를 꺼내 소비 = 정렬, 그룹핑, 집계값을 구하는 등의 작업을 한다)

 

분명 우리는 서버프로세스를 2개 가지고 병렬처리하기로 했는데

QC 는 작업반장이라 제외하더라도 지금 프로세스를 P000, 001, 002, 003 이렇게 4개를 쓰고 있다.

 

# 병렬도 = 2

# 서버 프로세스 = 병렬도 * 2 = 2 X 2 = 4

 

그래서 서버프로세스를 4개 쓰고 있는 것

 

# 통신 채널 수 = 병렬도 ** 2 = 2 ** 2 = 4

(통신채널 : QC 와 서버프로세스들 사이의 연결고리)

 

칠판 그림

더보기

예를 들어, 테이블에서 1000건의 데이터를 찾아야 한다고 하자.

1000건이나 되는 데이터는 혼자 찾는 것보다 여럿이 나눠서 찾는 것이 더 빠르기 때문에

QC 는 4개의 프로세스 P000, P001, P002, P003 에 250건씩 일거리를 주면서 데이터를 찾아오라고 시키고

각 프로세스들은 찾아온 250건 데이터들을 QC 에 다시 전달한다.

 

그런데 프로세스들이 전달한 1000건 데이터를 QC 혼자서 정렬하려고 하니 너무 힘들다.

이럴 때는: 프로세스들 각각이 자기들이 모아온 데이터들을 먼저 정렬한 다음

QC 에 전달하도록 하면 된다. (이러면 QC 는 merge 만 하면 됨)

 

하지만 이건 데이터가 작으면 문제가 없는데

프로세스들이 모아온 데이터들이 너무 클 때는 부하가 많이 발생한다.

또 프로세스들 각각이 가져온 데이터들에 중복값이 많이 들어있으면

QC 가 다시 정렬해야 하는데 QC 입장에서는 이게 너무 힘들다.

 

해결책: 프로세스들을 역할분담시키면 된다.

테이블에서 1천 건의 데이터를 뽑아와야 한다고 할 때

 

1-500
501-1000

1행부터 500행까지의 데이터는 P002 가 가져오도록 하고
501행부터 1000행까지의 데이터는 P003이 가져오도록 한다.
(P002 & P003 = 데이터 추출 팀  = server set = 서버집합 1)
데이터 추출팀이 일을 마치면 > 이제 그 수집한 데이터들을 정렬팀에 넘겨주고
정렬팀이 작업할 수 있도록 한다.
(P000 & P001 = 데이터 정렬 팀 = server set = 서버집합 2)

 

P002, P003 은 데이터 수집 팀

P000, P001 은 데이터 정렬 팀

P002와 P003이 정렬팀에 데이터를 전달해줄 때

P000에는 A-M 사이의 데이터만 정렬하라고 주고, P001에는 N-Z 사이의 데이터만 정렬하라고 주면

P000은 A-M 사이의 데이터만 정렬하면 되고 P001은 N-Z 사이의 데이터만 정렬하면 된다.

이렇게 정렬한 결과를 QC 로 전달하면 → QC 는 merge 만 하면 된다.


3교시

 

아까의 뷰 조회문을 다시 살펴보자.

select tq_id, server_type, process, num_rows, bytes, waits
from v$pq_tqstat
order by tq_id, decode(substr(server_type, 1, 4), 'RANG', 1, 'Prod', 2, 'Cons', 3), process;

 

PROCESS 컬럼을 보면 프로세스들의 목록이 나온다.

 

맨 위에서부터

P002, P003: 생산자 = 데이터 추출 팀 = 병렬서버집합 1

num_rows 컬럼을 보면 각 프로세스들이 일을 얼마나 많이 했는지 볼 수 있는데

P002는 데이터 56692건 추출했고 P003은 데이터 50308건 추출함...

수행결과가 이렇게 차이나는 건 아마 블록을 기준으로 나누는데

블록마다 HWM 까지 사용한 건수가 달라서 그런 걸로 추측됨.

 

P000, P001: 소비자 = 데이터 정렬 팀 = 병렬서버집합 2

P000은 A-M 까지의 데이터를 53000 건 정렬

P001은 N-Z 까지의 데이터를 54000 건 정렬

 

그리고 방금 전까지 소비자였던 P000과 P001이 생산자가 되어서

정렬 결과 set 을 QC 에게 전달 (생산자와 소비자는 뒤바뀔 수도 있다.)

1 2 3 4 5
  P → P * 소비자에서 → 생산자로 갑자기 돌변 P → S *  
생산자 (Producer) *   소비자 (Consumer) * 생산자 (Producer) *   소비자 (Consumer) *
P002
P003
  P000 (A-M)
P001 (N-Z)
P000(A-M)
P001(N-Z)
  QC
데이터 추출
병렬서버집합 1
테이블 큐 * :
TQ10000
데이터 정렬
병렬서버집합 2
정렬 결과 set 을
QC 에게 전달
테이블 큐 * :
TQ10001
생산자로부터 받은
각각의 정렬 결과를
merge 후
유저에게 전달

 

* 생산자 (Producer): 작업을 생성, 데이터 추출, 데이터를 추출해서 버퍼에 저장

* 소비자 (Consumer): 작업을 처리, 버퍼에 있는 데이터를 꺼내 소비 (정렬, 그룹 작업 수행)

* 테이블 큐: 프로세스 간 통신, 즉 메시지 또는 데이터를 전송하기 위한 통신, 파이프라인 (pipeline)

                    (실행계획의 Name 컬럼에서 볼 수 있다.)

 

* P → S : Parallel to Serial (3행)
  (각 병렬 서버 프로세스가 처리한 데이터를 코디네이터 QC 에게 전송할 때 serial 하게 전송한다는 뜻)
  3행을 보면 RANDOM, PQ Distrib 은 QC (RAND) 라고 나오는데 이건 Order by 되지 않고 무작위로 전송되었다는 뜻
  즉, RANDOM 은 정렬이 일어나지 않았을 때 표시되며, 병렬 프로세스들이 무순위로 QC 에게 데이터를 전송한다.

 

* P → P : Parallel to Parallel
  데이터 정렬, 또는 데이터를 그룹핑하거나 조인을 위해 동적으로 파티셔닝할 때 사용
  첫번째 병렬 서버 집합이 읽거나 가공한 데이터를 두번째 병렬 서버 집합에 전송


 

4교시

 

HR@ora11g>

select /*+ full(e) parallel(e 2) */ department_id, count(*) from emp e
group by department_id;

 

HR@ora11g>
select * from table(dbms_xplan.display_cursor(null, null, 'allstats last parallel'));

 

HR@ora11g>
select tq_id, server_type, process, num_rows, bytes, waits
from v$pq_tqstat
order by tq_id, decode(substr(server_type, 1, 4), 'RANG', 1, 'Prod', 2, 'Cons', 3), process;

 

이상한 점: P000과 P001이 처리한 데이터의 수가 갑자기 줄어들었다가 > 다시 12건으로 늘어났다.

왜 이러는지 실행계획에서 힌트를 찾아보자.

 

hash group by 가 2번 발생:

이건 데이터 추출팀에서 데이터를 수집하면서 + 추출한 데이터를 group by 까지 하고 있었음을 의미한다.

 

그리고 나서 수집한 데이터를 정렬팀에 전달할 때

이미 그룹핑한 데이터를 (n 개의 프로세스들에, 서로 겹치지 않도록) 주고

정렬팀에서 다시 그룹핑한다.

 

이래서 맨 처음에 12건이 나왔다가 > 나중에 다시 6건으로 줄어들었다가 다시 12건이 되었던 것

 

 

# 추출팀은 추출만 하고, 정렬팀에서 group by 하도록 힌트로 유도하기: no_gby_pushdown

 

HR@ora11g> select /*+ full(e) parallel(e 2) no_gby_pushdown */ department_id, count(*) from emp e
group by department_id;  2

 

select * from table(dbms_xplan.display_cursor(null, null, 'allstats last parallel'));

 

select tq_id, server_type, process, num_rows, bytes, waits
from v$pq_tqstat
order by tq_id, decode(substr(server_type, 1, 4), 'RANG', 1, 'Prod', 2, 'Cons', 3), process;

 

group by pushdown 을 하지 않았을 때: 

 

(※ select /*+ full(e) parallel(e 2) */ * from emp e
order by last_name; --- 이렇게 하면 group by pushdown 이 돌아간다.)

더보기

# group by pushdown 적용
원래 수행되어야 하는 group by 는 ID 컬럼 기준으로 3번이지만
ID 6번에서 먼저 group by 가 수행되었다.
그 이유는 : ID 5번의 TQ10000에게 데이터를 전달하기 전에 데이터를 줄여서 성능을 향상시키기 위함이다.

 

HR@ora11g>

select /*+ full(e) parallel(e 2) */ * from emp e
order by last_name;

107000 rows selected.

 

HR@ora11g> select * from table(dbms_xplan.display_cursor(null, null, 'allstats last parallel'));


5교시

 

리스트 파티션 테이블을 만들어보자.

 

HR@ora11g>

drop table hr.emp_part purge;

 

HR@ora11g>

drop table hr.dept_part purge;

 

HR@ora11g>
create table hr.emp_part
partition by list(department_id)
(partition p_dept_1 values(10, 20, 30, 40),
 partition p_dept_2 values(50),
 partition p_dept_3 values(60, 70, 80, 90, 100, 110),
 partition p_dept_4 values(default))
as select * from hr.employees;

Table created.

 

HR@ora11g>

create table hr.dept_part
partition by list(department_id)
(partition p_dept_1 values(10, 20, 30, 40),
 partition p_dept_2 values(50),
 partition p_dept_3 values(60, 70, 80, 90, 100, 110),
 partition p_dept_4 values(default))
as select * from hr.departments;

Table created.

 

HR@ora11g>

exec dbms_stats.gather_table_stats('HR', 'EMP_PART', granularity => 'auto')

PL/SQL procedure successfully completed.

 

HR@ora11g>
exec dbms_stats.gather_table_stats('HR', 'DEPT_PART', granularity => 'auto')

PL/SQL procedure successfully completed.

 

HR@ora11g>

select partition_name, high_value, tablespace_name, num_rows, blocks, avg_row_len
from user_tab_partitions
where table_name = 'EMP_PART';

 

HR@ora11g>

select * from user_part_key_columns where name = 'EMP_PART';

 

HR@ora11g>

select partition_name, high_value, tablespace_name, num_rows, blocks, avg_row_len
from user_tab_partitions
where table_name = 'DEPT_PART';

 

HR@ora11g>

select * from user_part_key_columns where name = 'DEPT_PART';

 

HR@ora11g>

select /*+ leading(d, e) use_hash(e) full(d) full(e) parallel(d 2) parallel(e 2) */
e.employee_id, e.last_name, e.salary, d.department_id, d.department_name
from dept_part d, emp_part e
where e.department_id = d.department_id;

106 rows selected.

 

select * from table(dbms_xplan.display_cursor(null, null, 'allstats last parallel partition'));

선생님 결과와 다른 화면이 나옴... 선생님은 6행까지밖에 없는데...

 

★ full partition wise join

- 조인하려는 두 테이블에 조인 키 컬럼을 기준으로 파티션된 경우

- 데이터를 재분배할 필요가 없다.

- pq_distribute(inner 테이블, outer table distribution 방식, inner table distribution 방식)

- pq_distribute(e, none, none)

  : full partition wise join 으로 유도할 때 사용

    + 양쪽 테이블 모두 조인 컬럼에 대해 같은 기준으로 파티셔닝되어 있을 경우 사용한다.

 

다시 힌트 써서 제대로 된 결과가 나오도록 유도해보기: pq_distribute(e, none, none) 는 재분배 힌트

HR@ora11g>

select /*+ leading(d, e) use_hash(e) full(d) full(e) parallel(d 2) parallel(e 2) pq_distribute(e, none, none) */
e.employee_id, e.last_name, e.salary, d.department_id, d.department_name
from dept_part d, emp_part e
where e.department_id = d.department_id;

106 rows selected.

 

select * from table(dbms_xplan.display_cursor(null, null, 'allstats last parallel partition'));

힌트를 다시 썼더니 제대로 된 결과가 나왔다. (아까는 3행의 list all 이 없었는데 지금은 생김)

 

HR@ora11g>

select tq_id, server_type, process, num_rows, bytes, waits
from v$pq_tqstat
order by tq_id, decode(substr(server_type, 1, 4), 'RANG', 1, 'Prod', 2, 'Cons', 3), process;

 

더보기

HR@ora11g>

select partition_name, high_value, tablespace_name, num_rows, blocks, avg_row_len
from user_tab_partitions
where table_name = 'EMP_PART';

 

HR@ora11g>

select partition_name, high_value, tablespace_name, num_rows, blocks, avg_row_len
from user_tab_partitions
where table_name = 'DEPT_PART';


6교시

 

★ partial partition wise join

- 조인 테이블 중 한 쪽에만 파티셔닝이 되어 있을 때

- 파티셔닝이 되어있지 않은 다른 쪽 테이블을, 파티셔닝이 되어있는 테이블과 같은 기준으로 파티셔닝한 다음

  풀 파티션 와이즈 조인 full partition wise join 을 수행한다.

- 동적 파티셔닝을 위한 데이터 재분배가 필요하다.

- pq_distribute(inner 테이블(별칭), outer table distribution 방식, inner table distribution 방식)

- pq_distribute(e, none, partition): inner 테이블을 outer 테이블 파티션 기준에 따라 파티셔닝하라는 뜻

  당연히 outer 테이블 조인 키 컬럼에 대해 파티셔닝되어 있을 때 작동된다.

  nonepartition 이 서로 뒤바뀌지 않도록 주의!!!!!!!!!!!!!!!!!!!!!!!!!!

 

테이블 만들기

 

HR@ora11g> drop table hr.emp_non purge;
Table dropped.

 

HR@ora11g> create table hr.emp_non as select * from hr.employees;
Table created.

 

HR@ora11g>

select /*+ leading(d, e) use_hash(e) full(d) full(e) parallel(d 2) parallel(e 2) pq_distribute(e, none, partition) */
e.employee_id, e.last_name, e.salary, d.department_id, d.department_name
from dept_part d, emp_non e
where e.department_id = d.department_id;

106 rows selected.

 

HR@ora11g>

select * from table(dbms_xplan.display_cursor(null, null, 'allstats last parallel partition'));

 

HR@ora11g>

select tq_id, server_type, process, num_rows, bytes, waits
from v$pq_tqstat
order by tq_id, decode(substr(server_type, 1, 4), 'RANG', 1, 'Prod', 2, 'Cons', 3), process;

 

 

# pq_distribute(epartitionnone)

# partial partition wise join 일 때 full partition wise join 으로 수행하기 위해서 사용된다.

   outer 테이블을 inner 테이블 파티션 기준에 따라 파티셔닝하라는 뜻

 

부서 테이블 만들기

 

HR@ora11g>

create table hr.dept_non as select * from hr.departments;
Table created.

 

HR@ora11g>

select /*+ leading(d, e) use_hash(e) full(d) full(e) parallel(d 2) parallel(e 2) pq_distribute(e, partition, none) */
e.employee_id, e.last_name, e.salary, d.department_id, d.department_name
from dept_non d, emp_part e
where e.department_id = d.department_id;

106 rows selected.

 

HR@ora11g>

select * from table(dbms_xplan.display_cursor(null, null, 'allstats last parallel partition'));

 

# 양쪽 테이블이 둘다 빅테이블인데 둘다 파티셔닝되어 있지 않을 경우: 동적 파티셔닝

 

★ 동적 파티셔닝

- 어느 한쪽도 조인 컬럼에 대해 파티셔닝이 되어있지 않은 상황

- 양쪽 테이블 모두 대용량일 때

 

# pq_distribute(e, hash, hash) : 조인 키 컬럼을 해시함수에 적용하고, 거기서 반환된 값을 기준으로

                                                   양쪽 테이블을 동적으로 파티셔닝하라는 뜻

 

HR@ora11g>

select /*+ leading(d, e) use_hash(e) full(d) full(e) parallel(d 2) parallel(e 2) pq_distribute(e, hash, hash) */
e.employee_id, e.last_name, e.salary, d.department_id, d.department_name
from dept_non d, emp_non e
where e.department_id = d.department_id;

106 rows selected.

 

HR@ora11g>

select * from table(dbms_xplan.display_cursor(null, null, 'allstats last parallel partition'));

 

★ broadcast

- 두 테이블이 모두 파티셔닝되지 않은 경우

- 둘 중 한 데이터 집합은 매우 작을 때 : 그 한 쪽은 굳이 파티셔닝할 필요가 없다. (그냥 스캔해버리는 것이 낫다)

- 브로드캐스트되는 데이터 집합이 매우 작을 때 유용하다.

 

예를 들어, d 테이블은 대용량인데 e 테이블은 작다고 할 때

outer(build) = dept_non, inner = emp_non

 

# pq_distribute(e, broadcast, none): 작은 테이블을 큰 테이블 쪽으로 브로드캐스트한다.

 

HR@ora11g>

select /*+ leading(d, e) use_hash(e) full(d) full(e) parallel(d 2) parallel(e 2) pq_distribute(e, broadcast, none) */
e.employee_id, e.last_name, e.salary, d.department_id, d.department_name
from dept_non d, emp_non e
where e.department_id = d.department_id;

106 rows selected.

 

HR@ora11g>

select * from table(dbms_xplan.display_cursor(null, null, 'allstats last parallel partition'));

 

select tq_id, server_type, process, num_rows, bytes, waits
from v$pq_tqstat
order by tq_id, decode(substr(server_type, 1, 4), 'RANG', 1, 'Prod', 2, 'Cons', 3), process;

 

P002만 일하고 P003은 전혀 일하고 있지 않다.

 

'오라클 퍼포먼스 튜닝' 카테고리의 다른 글

2024년 2월 27일  (1) 2024.02.27
2024년 2월 22일  (1) 2024.02.22
2024년 2월 15일  (1) 2024.02.15
2024년 2월 14일 5교시 + 6교시  (0) 2024.02.14
2024년 2월 14일 4교시  (0) 2024.02.14

관련글 더보기