효율적인Sql작성방법 4주차

75
본본본 본본 본본본 본본본 본본본본본 . IT 본본본본 본본 본본본본 SQL 본본본본 4 본본 본본본본본 3 본 본본본

Transcript of 효율적인Sql작성방법 4주차

Page 1: 효율적인Sql작성방법 4주차

본서의 모든 이미지 출처는 생략합니다 .

IT 역량강화 과정효율적인 SQL 작성방법4 주차

시스템개발 3 팀 강희동

Page 2: 효율적인Sql작성방법 4주차

3 주차 Review

Page 3: 효율적인Sql작성방법 4주차

Driving 의 중요성

TABLE1 TABLE2 TABLE3

(10000 row)

(1000 row)

(2 row)

. . .

1 A2 C3 D4 K5 M6 F7 E8 M. . . .. . . .

A 가P 나C 라H 사 . . .E 마

라 10마 20

최소 10,000 회 이상 ACCESS

TABLE3 TABLE2 TA-BLE1

(10000 row)

(2 row)

라 10마 20

(1000 row)

A 가P 나C 라S 마 . . .E 마

1 A2 C3 D4 K5 M6 F7 E8 M. . . .. . . .

최대 6 회 이하 ACCESS

Page 4: 효율적인Sql작성방법 4주차

Optimizer

SQL Pars-ing

Optimiza-tion

Row-Source Execution

Parser OptimizerRow-SourceGenerator SQL EngineParsed

SQLExecution Plan

Row-Source

1.Query Trans-former2.Estimator3.Plan Generator

Page 5: 효율적인Sql작성방법 4주차

전체범위 VS 부분범위

전 체 범 위 처 리

2차가공

운반단위

• • • •

1차스캔

Full Range Scan 후 가공하여 Array Size 만큼 추출

부 분 범 위 처 리

2차가공

운반단위

1차스캔

조건을 만족하는 Row 수가 Ar-ray Size 에 도달되면 멈춤

Page 6: 효율적인Sql작성방법 4주차

전체범위 VS 부분범위

INDEX SCAN

FULL SCAN

Page 7: 효율적인Sql작성방법 4주차

RANDOM ACCESS

운반단위

INDEX (FLD)

.....

2

차가공

TAB TAB

운반단위

oxo

oox

o

x

.....

x

x

2

차가공

oo

Index Range Scan Full Table Scan

RANDOM ACCESS 가 많이 발생되면 I/O 효율이 떨어집니다 .

Page 8: 효율적인Sql작성방법 4주차

INDEX 의 중요성 !

테이블 드라이빙 우선순위부서 테이블 (100 건 )

부서번호 (PK)사원 테이블 (10 만건 )

사원번호 (PK)

부서번호 (FK)

조건 - 부서테이블 , 사원테이블에는 PK 인덱스만 존재- 전체 데이터 검색문제1 번 테이블이 먼저 드라이빙 하는게 유리할까요 ?2 번 테이블이 먼저 드라이빙 하는게 유리할까요 ?

-1 번 테이블이 먼저 드라이빙 될 경우부서 테이블을 100 건을 스캔하고서 사원 테이블을 10 만번 스캔100 X 100,000 = 1,000,000 ( 백만번 스캔 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!)

-2 번 테이블이 먼저 드라이빙 될 경우사원테이블을 10 만번 스캔하고서 부서 테이블을 스캔하는데 부서번호키가 Unique index 이기 때문에 1 번만 읽고 스캔100,000 X 1 = 100,000 ( 십만번 스캔 )

Page 9: 효율적인Sql작성방법 4주차

INDEX 손익분기점

가정전체 10,000 row1 block 당 평균 10 row전체 1,000 block

운반단위

INDEX (FLD)

.....

2

차가공

TAB TAB

운반단위

oxo

oox

o

x

.....

x

x

2

차가공

oo

Index Range Scan Full Table Scan

1,000 row read 를 위해 1,000 block access 낮은 Hit Ratio

10,000 row read 를 위해 1,000 block access 높은 Hit Ratio

인덱스 사용여부 고려사항Scan 범위Hit RatioClustering Factor

손익분기점(10 ~15%)

Page 10: 효율적인Sql작성방법 4주차

INDEX SCAN, FULL SCAN SWITCH

NULL 이럴 때만 사용 합시다 !- 미 확정 값을 표현하고자 할 때- 결합인덱스의 구성 컬럼이 된다면 NOT NULL!- 인덱스 조건 값으로 자주 사용 된다면 NOT NULL!

특정 값이 지나치게 많고 나머지 값만 주로 인덱스로 액세스A 사B 사C 사D 사E 사F 사

B

컬럼 값

CDEF

NULL TABLE FULL SCAN

INDEX RANGE SCAN

Page 11: 효율적인Sql작성방법 4주차

INDEX SCAN, FULL SCAN SWITCH

(78%)

4% 6% 7%5%

A

BC DE

COL1 분포도

KEYCOL1. . . .

TABLE1(10000 row) CREATE INDEX index_name

ON table_name (COL1);

COL1 = 'A' 를 그대로

COL1KEY . . . .

A. . . . . . . .

A. . . . . . . .

A. . . . . . . .

B. . . . . . . .

B. . . . . . . .

. . . .. . . . . . . .

COL1 ROWID

A . . . .

A . . . .

A . . . .

B . . . .

B . . . .

. . . . . . . .

TABLE1(10000 row)

INDEX1(10000 row)

COL1 = 'A' 를 COL1 NULL 로

COL1KEY . . . .

Null. . . . . . . .

Null. . . . . . . .

Null. . . . . . . .

B. . . . . . . .

B. . . . . . . .

. . . .. . . . . . . .

COL1 ROWID

B . . . .

. . . . . . . .

C . . . .

. . . . . . . .

TABLE1(10000 row)

INDEX1(2000 row)

Page 12: 효율적인Sql작성방법 4주차

INDEX 컬럼의 변형

SELECT * FROM EMP WHERE SUBSTR(DNAME,1,3) = 'ABC'

SELECT * FROM EMP WHERE DNAME LIKE 'ABC%'

SELECT * FROM EMPWHERE SAL * 12 = 12000000

SELECT * FROM EMPWHERE TO_CHAR(HIREDATE,'YYMMDD') = ‘130712'

SELECT * FROM EMP WHERE HIREDATE = TO_DATE(‘130712','YYMMDD')

SELECT * FROM EMP WHERE SAL = 12000000 / 12

SELECT * FROM EMPWHERE DEPTNO || JOB = '10SALESMAN'

SELECT * FROM EMPWHERE DEPTNO = '10' AND JOB = 'SALSMAN'

Page 13: 효율적인Sql작성방법 4주차

INDEX 컬럼의 변형

SELECT * FROM EMPWHERE NVL(COMM,0) < 100

?

SELECT * FROM EMPWHERE COMM < 100

SELECT * FROM EMP WHERE EMPNO BETWEEN 100 AND 200 AND NVL(JOB,'X') = 'CLERK'

SELECT * FROM EMP WHERE EMPNO BETWEEN 100 AND 200 AND JOB = 'CLERK'

컬럼 값에 NULL 이 존재하는 경우

해결방안 : NULL 값 0 으로 변경

Page 14: 효율적인Sql작성방법 4주차

INDEX 컬럼의 변형

SELECT * FROM EMPWHERE JOB = 'MANAGER'

SELECT * FROM EMPWHERE RTRIM(JOB) = 'MANAGER'

SELECT * FROM EMPWHERE EMPNO = 8978

SELECT * FROM EMP WHERE RTRIM(EMPNO) = 8978

SELECT CUSTNO, CHULDATE FROM CHULGOT WHERE CUSTNO LIKE 'DN%' AND RTRIM(STATUS) LIKE '9%'

SELECT CUSTNO, CHULDATE FROM CHULGOT WHERE CUSTNO LIKE 'DN%' AND STATUS LIKE '9%'

의도적인 SUPPRESSING

Page 15: 효율적인Sql작성방법 4주차

INDEX 컬럼의 변형

의도적인 SUPPRESSINGSELECT X.CUSTNO, CHULDATE, CUSTNAME FROM MECHUL1T X, MECHUL2T Y WHERE X.SALENO = Y.SALENO AND X.SALEDEPT = '710' AND Y.SALEDATE LIKE ‘1301%' 10 Sec

SELECT X.CUSTNO, CHULDATE, CUSTNAME FROM MECHUL1T X, MECHUL2T Y WHERE X.SALENO = Y.SALENO AND RTRIM(X.SALEDEPT) = '710' AND Y.SALEDATE LIKE ‘1301%' 1 Sec

SELECT X.ORDNO, ORDDATE, ITEM FROM ORDER1T X, ORDER2T Y WHERE X.ORDNO = Y.ORDNO AND X.ORDDATE LIKE ‘1301%' AND Y.ORDDEPT = '710' ORDER BY ORDDATE 13 Sec

SELECT X.ORDNO, ORDDATE, ITEM FROM ORDER1T X, ORDER2T Y WHERE RTRIM(X.ORDNO) = Y.ORDNO AND X.ORDDATE LIKE ‘1301%' AND Y.ORDDEPT = '710’ 1 Sec

연결고리 확인 ! 인덱스가 없으면 없는 쪽부터 드라이빙 !!( 중요 !)

Page 16: 효율적인Sql작성방법 4주차

INDEX 컬럼의 변형

SELECT * FROM SAMPLET WHERE NUM LIKE '9410%'

CREATE TABLE SAMPLET ( CHR VARCHAR2(10), NUM NUMBER (12,3), VAR VARCHAR2(20), DAT DATE)

SELECT * FROM SAMPLET WHERE CHA = 10

SELECT * FROM SAMPLET WHERE TO_NUMBER(CHA) = 10

SELECT * FROM SAMPLET WHERE TO_CHAR(NUM) LIKE '9410%'

SELECT * FROM SAMPLET WHERE DAT = '01-JAN-94'

SELECT * FROM SAMPLET WHERE DAT = TO_DATE('01-JAN-94')

DATA TYPE 의 변형

Page 17: 효율적인Sql작성방법 4주차

INDEX 컬럼의 변형

DATA TYPE 의 변형 TABLE ACCESS FULL CHULGOT

1 row, 28.5 sec

SQL> SELECT SUM(UNCOST) FROM CHULGOT WHERE STATUS = 90

SORT AGGREGATE TABLE ACCESS BY ROWID CHULGOT INDEX RANGE SCAN CH_STATUS 1 row,

0.15 sec

SQL> SELECT SUM(UNCOST) FROM CHULGOT WHERE STATUS = '90'

SQL> SELECT CHULNO, CUSTNO, UNCOST FROM CHULGOT WHERE CFMDEPT LIKE '71%'

NESTED LOOPS TABLE ACCESS FULL ORDER1T TABLE ACCESS BY ROWID CHULGOT INDEX RANGE SCAN CH_CFMDEPT

rows,71 sec

SQL> SELECT ORDNO, CHULNO, STATUS FROM ORDER1T X, CHULGOT Y WHERE X.CUSTNO = Y.CUSTNO AND X.ORDDEPT = Y.CFMDEPT AND y.CHULDATE LIKE ‘1307%'

NUMBER type

TABLE ACCESS FULL CHULGOT

rows, 30 sec

NUMBER > (CHAR or VARCHAR)

Page 18: 효율적인Sql작성방법 4주차

INDEX 활용기준

INDEX 적용기준6 블럭 이상의 테이블에 적용 (6 블럭 이하는 연결고리만 )

컬럼의 분포도가 10~15% 이내인 경우 적용

분포도가 범위 이내더라도 절대량이 많은 경우에는 클러스터링 검토

분포도가 범위 이상이더라도 부분범위처리를 목적인 경우 적용

인덱스만 사용하여 해결하고자 하는 경우 분포도가 나쁘더라도 적용 가능

Page 19: 효율적인Sql작성방법 4주차

INDEX 활용기준

INDEX 선정기준 분포도가 좋은 컬럼은 단독적으로 생성하여 활용도 향상 자주 조합되어 사용되는 경우는 결합인덱스 생성 각종 엑세스 경우의 수를 만족하도록 인덱스 간의 역할 분담 가능한 수정이 빈번하지 않은 컬럼 기본키 및 외부키 ( 조인의 연결고리가 되는 컬럼 )

결합 인덱스의 컬럼 순서 선정에 주의

Page 20: 효율적인Sql작성방법 4주차

INDEX 활용기준INDEX 선정절차

• 해당 테이블 사용하는 모든 쿼리의 액세스 유형 조사1. 해당 테이블의 액세스 유형조사

• 인덱스 후보로 어떤 컬럼이 좋을지 선정하고 각 컬럼에 데이터 분포도 분석2. 대상 컬럼의 선정 및 분포도 분석

• FOR 문 안에서 실행되는 쿼리 일 경우 최적에 액세스 경로를 탈 수 있게 최적화3. 반복 수행되는 액세스 경로의 해결

• 데이터량이 많은 경우 검토 ( 초기에는 적용하기 쉬우나 운영 중에는 초기에 비해 적용이 어려움 )4. 클러스터링 검토

• 컬럼의 순서를 결정5. 인덱스 컬럼의 조합 및 순서의 결정

• 잘못된 쿼리로 인해 인덱스 적용이 안 될 수 있음 . 이런 쿼리들을 최적화 쿼리로 수정• 모든 작업이 완료되면 일괄 적용6. 시험생성 및 테스트 그리고 일괄 수정

Page 21: 효율적인Sql작성방법 4주차

INDEX 활용기준결합 INDEX 순서 절차 항상 사용하는가 ?

항상 EQUAL 로 사용되는가 ?

분포도가 좋은 컬럼 우선

SORT 순서는 ?

어떤 컬럼을 추가 ?( 후보선수 )

Page 22: 효율적인Sql작성방법 4주차

추가된 인덱스가 미치는 영향

SELECT * FROM TAB1 WHERE A = '10' AND B = ‘130415' AND C = '123'

AB CINDEX1 IN-DEX2

A = '10‘B = ‘130415'

C = '123'

(INDEX1 사용 )

D column 추가

ABD CINDEX1 IN-DEX2

C = '123'(INDEX2 사용 )

A = '10‘B = ‘130415‘D LIKE ‘A%’

Page 23: 효율적인Sql작성방법 4주차

추가된 인덱스가 미치는 영향예제

CHULITEM table Primary Key : CHULNO + ORDNO + ITEMSQL> SELECT CHULNO, ORDNO, ITEM, CHULQTY FROM CHULITEM WHERE CHULNO = '2565' AND ORDNO = '8584' AND LOT = 'P0009'

1 rows, 0.01sec

TABLE ACCESS BY ROWID CHULITEM INDEX RANGE SCAN PK_CHULITEM

SQL> SELECT CHULNO, ORDNO, ITEM, CHULQTY FROM CHULITEM WHERE CHULNO = '2565' AND ORDNO = '8584' AND LOT = 'P0009'

1 rows, 37.7sec

SQL> CREATE INDEX CI_LOT ON CHULITEM (LOT)

TABLE ACCESS BY ROWID CHULITEM INDEX RANGE SCAN CI_LOT

SQL> SELECT CHULNO, ORDNO, ITEM, CHULQTY FROM CHULITEM WHERE CHULNO = '2565' AND ORDNO = '8584' AND LOT = 'P0009'

1 rows,0.01 sec

SQL> CREATE INDEX CI_LOT_ITEM ON CHUITEM (LOT,ITEM)

TABLE ACCESS BY ROWID CHULITEM INDEX RANGE SCAN PK_CHULITEM

Page 24: 효율적인Sql작성방법 4주차

4 주차

Page 25: 효율적인Sql작성방법 4주차

JOIN

기본 실력 Test

조인에 대한 이해문제상품명을 가져 올 때 어떤 방법이 비용을 절약 할 수 있는 방법인가 ?

상품 테이블 (100 건 )상품번호 (PK)

상품명 VARCHAR2(4BYTE)

주문 테이블 (10 만건 )주문번호 (PK)

상품번호 (FK)

① 상품테이블에 상품명을 추가해서 주문테이블과 조인해서 검색

SELECT * FROM 주문 , 상품WHERE 주문 . 상품번호 = 상품 . 상품번호

주문 테이블 (10 만건 )주문번호 (PK)

상품명 VARCHAR2(4BYTE)

② 주문테이블에 상품명을 추가해서 주문테이블만 검색

SELECT * FROM 주문

상품명 컬럼 4byte 를 추가하게 되면 1Row 는 4x100,000 = 400,000

상품명 컬럼 4byte 를 추가하게 되면 1Row 는 4x100 = 400

Page 26: 효율적인Sql작성방법 4주차

수행속도의 결정요소 DRIVING!

TAB2

K . . . . . . . A . . . . . . . . . . . . . . . D . . . . . . . Z . . . . . . .

KEY2 FLD . . .

FLD . . . KEY1. . . . . . . . . A. . . . . . . . . D. . . . . . . . . B. . . . . . . . . .. . . . . . . . . K

K . . . . . . . A . . . . . . . . . . . . . . . D . . . . . . . Z . . . . . . .

KEY2 FLD . . .

. . . . . . . . . A. . . . . . . . . D. . . . . . . . . B. . . . . . . . . .. . . . . . . . . K

FLD . . . KEY1

INDEX 있음

TAB1

INDEX 있음TAB1 TAB2

INDEX 있음 INDEX 없음- 인덱스가 한쪽만 있으면 FULL SCAN 이 발생- 두쪽 다 인덱스가 없으면 SORT MERGE 방법으로 처리

Page 27: 효율적인Sql작성방법 4주차

ACCESS 량에 따른 처리 속도

ACCESS 량이 많음

운반단위

INDEX(FLD1)

TAB1 TAB2INDEX(KEY2)

FLD1='10'

KEY2 = KEY1

o

x

5000 row

x

xx

x

.

.

.

.

100 row 50 row

.

.

.

.

.

.

.

.

x oo

FLD2 like ‘A%’

ACCESS 량이 적음

운반단위

INDEX(FLD2)

INDEX(KEY1)

KEY1 = KEY2

FLD2 like 'A%'

100 row

.

.

.

.

70 row50 row

.

.

.

.....

.

.

.

.

x

TAB1 TAB2

oo

FLD1 =‘10’

SELECT A.FLD1, ..., B.FLD1,...

FROM TAB2 B, TAB1 AWHERE A.KEY1 = B.KEY2 AND B.FLD2 like 'A%' AND A.FLD1 = '10'

15 Sec 1 Sec

Page 28: 효율적인Sql작성방법 4주차

ACCESS 량에 따른 처리 속도

ACCESS량이 많은 방식을 ACCESS량이 적은 방식으로 실행되게 하려면위 쿼리를 어떻게 변경 해야 할까요 ?

Page 29: 효율적인Sql작성방법 4주차

JOIN 과 LOOP QUERY

JOIN LOOP-QUERY

운반단위SQL

SQL

SQL

TAB1 TAB2

.

.

.

.

SQL

SQL

2

차가공

....

....

2

차가공

운반단위

TAB1 TAB2

....

.

.

.

.

....

Page 30: 효율적인Sql작성방법 4주차

for(i = 0; i < 100; i++){ for(j = 0; j < 100; j++){

// Do Anything.. }}

Nested Loops 조인

Nested Loops = For 문

Page 31: 효율적인Sql작성방법 4주차

Nested Loops 조인

운반단위

INDEX(FLD1)

TAB1 TAB2INDEX(KEY2)

FLD1='AB'

TABLE ACCESS BY ROWID

KEY2= KEY1

TABLE ACCESS BY ROWID

FLD2 ='10' check

oo

o

x

SELECT A.FLD1, ..., B.FLD1,... FROM TAB1 A, TAB2 BWHERE A.KEY1 = B.KEY2 AND A.FLD1 = 'AB' AND B.FLD2 = '10'

• 모든 DBMS 에서 사용• 부분범위처리 가능• 먼저 처리되는 테이블의 처리범위에 따라 처리량 결정• 랜덤 (Random) 액세스 위주 • 연결고리 상태에 따라 영향이 큼 • 주로 좁은 범위 처리에 유리

Page 32: 효율적인Sql작성방법 4주차

Nested Loops 조인

SELECT /*+ ORDERED USE_NL(E) */ E.EMPNO, E.ENAME, D.DNAME, E.JOB, E.SAL FROM DEPT D, EMP E WHERE E.DEPTNO = D.DEPTNO …………… ① AND D.LOC = 'SEOUL' …………… ② AND D.GB = '2' …………… ③ AND E.SAL >= 1500 …………… ④ ORDER BY SAL DESC

* pk_dept : dept.deptno * dept_loc_idx : dept.loc * pk_emp : emp.empno * emp_deptno_idx : em-p.deptno * emp_sal_idx : emp.sal

인덱스 구조

문제 ! 조건 비교 순서가 어떻게 사용될까요 ?Execution Plan --------------------------------------------------- 0 SELECT STATEMENT 1 0 SORT ORDER BY 2 1 NESTED LOOPS 3 2 TABLE ACCESS BY INDEX ROWID DEPT 4 3 INDEX RANGE SCAN DEPT_LOC_IDX 5 2 TABLE ACCESS BY INDEX ROWID EMP 6 5 INDEX RANGE SCAN EMP_DEPTNO_IDX

 ② → ③ → ① → ④ 

Page 33: 효율적인Sql작성방법 4주차

Nested Loops 조인

SELECT /*+ ORDERED USE_NL(E) */ E.EMPNO, E.ENAME, D.DNAME, E.JOB, E.SAL FROM DEPT D, EMP E WHERE E.DEPTNO = D.DEPTNO …………… ③ AND D.LOC = 'SEOUL' …………… ① AND D.GB = '2' …………… ② AND E.SAL >= 1500 …………… ④ ORDER BY SAL DESC

① ② D.LOC = ‘SEOUL’ 의 범위가 넓으면 전체적인 속도 저하 발생 체크조건인 D.GB = ‘2’ 범위가 넓으면 결합인덱스 고려③ ④ E.DEPTNO, D.DEPTNO 각 컬럼이 데이터 타입이 일치하는지 확인 DRIVING 될 E.DEPT_NO 에 인덱스가 있는지 확인 E.SAL 범위가 넓으면 결합인덱스 고려

NL JOIN 이 효과적이지 못 할 때 HASH JOIN, SORT MERGE JOIN 고려

Page 34: 효율적인Sql작성방법 4주차

Nested Loops 조인

• 블록단위로 I/O 를 수행• 하나의 레코드만 읽어도 블록을 통째로 읽음• RANDOM ACCESS 는 빠르지만 비효율이 존재

대량의 데이터를 조인할 때 비효율적

• 대용량 데이터 처리 시 매우 치명적인 한계를 보임• 대용량이더라도 부분범위 처리 상황에서 빠른 속도를 낼 수 있음순차적 조인

• 다른 조인방식과 비교 했을 때 인덱스 구성 전략이 중요• 소량의 데이터를 처리 할 때 효율적 • Prefetch(Table,Index), Buffer Pinning 효과로 액세스 획기적 감소 (Non unique)• 가능한 Nested Loop 방식으로 처리하고 비효율적일 때 Hash 조인과 , Merge 조인 고려

온라인 환경에 적합한 조인

Nested Loop 특징

Random 액세스 향상

Page 35: 효율적인Sql작성방법 4주차

각 테이블을 조건에 맞게 정렬 한 후 Merge

Sort Merge 조인

운반단위

.

.

.

SORT

.........

.

.

.

SORT .

.

.

......

Page 36: 효율적인Sql작성방법 4주차

Sort Merge 조인 효율적인 SQL작성방법

옵티마이져 사용자

Nested Loop로 처리해

쓸만한 인덱스가 있나 ?.. 없네 ;; 소트머지 조인이나해쉬 조인을 써야겠다 ~

Page 37: 효율적인Sql작성방법 4주차

Sort Merge 조인

SELECT /*+USE_MERGE(A,B)*/ A.FLD1, ..., B.FLD2,... FROM TAB1 A, TAB2 BWHERE A.KEY1 = B.KEY2 AND A.FLD1 = 'AB' AND B.FLD2 = '10'

INDEX(FLD1)

TAB1 TAB2

FLD1='AB'

TABLE AC-CESS BY ROWID

운반단위

.

.

.

SORT

INDEX(FLD2)

FLD2='10'

TABLE ACCESS BY ROWID

a.KEY1= b.KEY2 를 조건으로 Merge

.........

.

.

.

SORT.

.

.

......

• 전체범위 처리 (First, Second) • 인덱스 유무에 영향을 받지 않음• 주로 넓은 범위 처리에 유리• 조인 컬럼에 인덱스가 없을 때 유리• NL 과 같은 스캔 액세스 위주• PGA 에있는 SQLAREA 사용하여 래치 획득 과정이 없음

Page 38: 효율적인Sql작성방법 4주차

Sort Merge 조인

Sort Merge( 뭐지 ?) 단계 1. Sort 단계 : 양쪽 집합을 조인 컬럼 기준으로 정렬2. Merge 단계 : 정렬된 양쪽 집합을 서로 머지

Point !! 정렬해서 merge 한다는 점만 다를 뿐 수행과정은 Nested Loop 와 다르지 않음왜 ? Sort Area 때문에 ~

= SORT!

Page 39: 효율적인Sql작성방법 4주차

PGA<- SQL AREA

ORACLE 에서 사용 하는 메모리SGA : 모든 서버 및 백그라운드 프로세스에 의해 공유

PGA : 각 서버 프로세스에 대한 데이터 및 제어정보를 포함공용으로 쓰는 메모리

독립적으로 사용되는 메모리

Page 40: 효율적인Sql작성방법 4주차

Sort Merge 조인

같이 사용 하는 공간

모든 유저에게 할당하는 각각의 프로세스가 독점으로 사용하는 공간

Page 41: 효율적인Sql작성방법 4주차

Sort Merge 조인

정렬공간(Sort Area)

세션정보 커서상태정보 변수저장공간PGA

ORDER BYGROUP BY

ROLLUPDISTINCT

UNION MINUSINSERT SELECT인덱스 생성

BITMAP 연산 수행SORT MERGE 조인HASH JOIN

통계정보

독립적인 메모리 공간이어서 래치 획득 과정이 없어서 빠름

Page 42: 효율적인Sql작성방법 4주차

Sort Merge 조인

Sort Merge Join…… 언제 어떻게 써야 좋은 거야 ?

Page 43: 효율적인Sql작성방법 4주차

Sort Merge 조인First 테이블에 소트 연산을 대체할 인덱스가 있을 때

CREATE INDEX dept_idx ON dept(loc, deptno);CREATE INDEX emp_idx ON emp(job, deptno);

인덱스 생성

SELECT /*+ ordered use_merge(e) */ * FROM dept d, emp e WHERE d.deptno = e.deptno AND d.loc = 'CHICAGO’ AND e.job = 'SALESMAN’ ORDER BY e.deptno;

쿼리 실행

실행 계획

SORT 오퍼레이션 줄이기 !!FIRST 테이블 부분범위 처리 유도하기

Page 44: 효율적인Sql작성방법 4주차

Sort Merge 조인조인할 First 집합이 이미 정렬돼 있을 때GROUP BY, ORDER BY, DISTINCT 를 이용해서 이미 정렬 된 경우 효율적 !

SELECT /*+ ORDERED USE_MERGE(D) */ D.DEPTNO, D.DNAME, E.AVG_SALFROM (SELECT DEPTNO, AVG(SAL) AVG_SAL FROM EMP GROUP BY DEPTNO) E , DEPT DWHERE E.DEPTNO = D.DEPTNO

10g R2 에서 도입된 hash group by 로 효율이 낮아 지기 때문에 Sort group by 로 유도 해야 함 !

쿼리 실행

쿼리 실행

Page 45: 효율적인Sql작성방법 4주차

Sort Merge 조인조인할 First 집합이 이미 정렬돼 있을 때GROUP BY, ORDER BY, DISTINCT 를 이용해서 이미 정렬 된 경우 효율적 !

SELECT /*+ ORDERED USE_MERGE(D) */ D.DEPTNO, D.DNAME, E.AVG_SALFROM (SELECT DEPTNO, AVG(SAL) AVG_SAL FROMEMP GROUP BY DEPTNO ORDER BY DEPTNO) E , DEPT DWHERE E.DEPTNO = D.DEPTNO

9i 에서는 Sort group by 로 처리 됨 (hash group by 가 없음 )

쿼리 실행

쿼리 실행

Page 46: 효율적인Sql작성방법 4주차

Sort Merge 조인조인 조건식이 등치 (=) 조건이 아닐 때

Hash 조인은 = 조건만 사용 가능 하지만 merge 조인은 between, <, <=, >, >= 조건도 사용가능 !

SELECT /*+ ORDERED USE_MERGE(E) */ D.DEPTNO, D.DNAME, E.EMPNO, E.ENAME FROM DEPT D, EMP E WHERE D.DEPTNO <= E.DEPTNO WHERE D.DEPTNO >= E.DEPTNO

ASCDESC

Page 47: 효율적인Sql작성방법 4주차

NESTED LOOP, SORT MEGE JOIN 예제MERGE JOIN SORT JOIN TABLE ACCESS FULL CHULGOT SORT JOIN TABLE ACCESS FULL CUSTOMER

SQL> SELECT X.CUSTNO,CHULDATE, CUSTNAME FROM CHULGOT X, CUSTOMER Y WHERE X.CUSTNO = Y.CUSTNO

5.44 sec

NESTED LOOPS TABLE ACCESS FULL CHULGOT TABLE ACCESS BY ROWID CUSTOMER INDEX UNIQUE SCAN PK_CUSTNO

0.02 sec

SORT GROUP BY MERGE JOIN SORT JOIN TABLE ACCESS FULL CHULGOT SORT JOIN TABLE ACCESS FULL CUSTOMER

SQL> SELECT NATION, SUM(CHULTIME) FROM CHULGOT X, CUSTOMER Y WHERE X.CUSTNO = Y.CUSTNO GROUP BY NATION

8.33 sec

SQL> SELECT /*+ RULE */ NATION, SUM(CHULTIME) FROM CHULGOT X, CUSTOMER Y WHERE X.CUSTNO = Y.CUSTNO GROUP BY NATION

SORT GROUP BY NESTED LOOPS TABLE ACCESS FULL CUSTOMER TABLE ACCESS BY ROWID CHULGOT INDEX RANGE SCAN CH_CUSTNO

17.5 sec

Page 48: 효율적인Sql작성방법 4주차

JOIN 방법의 결정

Nested

Loop

JOIN

좁 다

넓 다Driving

table결정

부분범위처리Check

조건

Sort MergeJOIN

넓 다

좁 다가 능

불가능유 리불 리

Driving 과 Check 조건 교환

가 능 Driving조건First_rows

불가능

상수를 추가로 넣는게유리한지 비교

All_rows

Page 49: 효율적인Sql작성방법 4주차

Hash 조인

Nested loop, Sort merge join 의 대안

HASH JOIN7.3

Page 50: 효율적인Sql작성방법 4주차

HASH JOIN 원리

2 개 테이블 중 작은 집합을 HashMap 으로 생성

큰 집합을 읽어서 해시테이블을 탐색하며 조인

-Nested Loop Join 처럼 Random 액세스 부하가 없음 .-Sort Merge Join 처럼 미리 양쪽 집합을 정렬하는 부담이 없음 .

-Hash 테이블 생성 시 많은 COST 가 발생됨 .-Hash Area 에 담길 정도의 크기로 만들어져야 성능이 향상 됨 .

Page 51: 효율적인Sql작성방법 4주차

Hash Join Build Input

옵티마이저의 실수

Page 52: 효율적인Sql작성방법 4주차

HASH JOIN 원리

SELECT /*+USE_HASH(D E) */ D.DEPTNO, D.DNAME, E.EMPNO, E.ENAME FROM SCOTT.DEPT D, SCOTT.EMP EWHERE D.DEPTNO = E.DEPTNO;

통계정보상 더 작은 테이블이기 때문

SELECT /*+LEADING(E) USE_HASH(D E) */ D.DEPTNO, D.DNAME, E.EMPNO, E.ENAME FROM SCOTT.DEPT D, SCOTT.EMP EWHERE D.DEPTNO = E.DEPTNO;

Page 53: 효율적인Sql작성방법 4주차

HASH JOIN 원리 효율적인SQL작성방법

HASH AREA 가 초과 될 때 옵티마이저의 생각 읽기

Grace 해시 조인 > Hybrid 해시 조인 / Recursive 해시 조인 (Nested Loop 해시 조인 )

Page 54: 효율적인Sql작성방법 4주차

HASH JOIN 원리Build input 키 값 중복이 많이 발생할 때 튜닝 방법

SELECT /*+USE_HASH(O F) */ COUNT(*) FROM ORDER O, CONTRACT F WHERE O.PRODUCT_CD = F.PRODUCT_CD AND O.ORDER_DT = F.CONTRACT_DT AND O.ORDER_NO IN (F.ORDER_NO_BUY, F.ORDER_NO_SELL); AND F.CONTRACT_DT = : 주문일자

SELECT /*+ GATHER_PLAN_STATISTICS USE_HASH(O F) */ COUNT(*) FROM ORDER O, (SELECT PRODUCT_CD, FILL_DT, ORDER_NO_BUY AS ORDER_NO FROM CONTRACT UNION ALL SELECT PRODUCT_CD, FILL_DT, ORDER_NO_SELL AS ORDER_NO FROM CONTRACT) F WHERE O.PRODUCT_CD = F.PRODUCT_CD AND O.ORDER_DT = F.CONTRACT_DT AND O.ORDER_NO = F.ORDER_NO AND F.CONTRACT_DT = : 주문일자

하나의 버킷에 많은 엔트리71 초

0.16 초

Page 55: 효율적인Sql작성방법 4주차

HASH JOIN 원리

HASH JOIN 사용 기준 한 쪽 테이블이 Hash Area 에 담겨야 함 .

Build Input 해시 키 컬럼에 중복 값이 거의 없어야 함 .

조인 컬럼에 적당한 인덱스가 없어 NL 조인이 비효율적일 때 조인 액세스량이 많아 Random 액세스 부하가 심할 때 소트머지조인을 하기에는 두 테이블이 너무 클 때 수행빈도가 낮고 쿼리 수행 시간이 오래 걸리는 대용량테이블 조인 할 때

Page 56: 효율적인Sql작성방법 4주차

Outer Join

Outer... Join...

Page 57: 효율적인Sql작성방법 4주차

Outer NL Join, Outer Sort Merge Join

Outer join 의 함정문제Optimizer 는 고객 테이블 , 주문 테이블 중 어느 테이블을 먼저 Driving 할 것인가 ?

고객 테이블 (100 건 )고객번호 (PK)

주문테이블 (1,000 만건 )주문번호 (PK)

고객번호 (FK)

SELECT * FROM 고객 , 주문WHERE 고객 . 고객번호 (+) = 주문 . 고객번호

고객테이블이 먼저 Driving 되어야 하지만Outer 조건 때문에 주문 테이블을먼저 Driving 하게 됨 . ( 키 존재 여부를 Outer 가 아닌쪽을 전체 조회 해봐야 알 수 있기 때문에 )

(+) 기호가 붙지 않은 테이블이 먼저 드라이빙 !!

Page 58: 효율적인Sql작성방법 4주차

Outer Join 제거 예제

튜닝 전 튜닝 후

Page 59: 효율적인Sql작성방법 4주차

Outer Join효율적인SQL작성방법

RIGHT OUTER HASH JOIN…!!!! (10g)

Page 60: 효율적인Sql작성방법 4주차

Outer Hash Join

매칭된 레코드는 결과집합에 삽입매칭되지 않은 레코드는 마지막에 붙임

Page 61: 효율적인Sql작성방법 4주차

Left Outer 조인 + Union All + Anti 조인 (Not Exists)

Full Outer Join

SELECT A. 고객 ID, A. 입금액 , B. 출금액FROM (SELECT 고객 ID, SUM( 입금액 ) 입금액 FROM 입금 GROUP BY 고객 ID)A ,(SELECT 고객 ID, SUM( 출금액 ) 출금액 FROM 출금 GROUP BY 고객 ID)BWHERE B. 고객 ID(+)=A. 고객 IDUNION ALLSELECT 고객 ID, NULL, 출금액FROM (SELECT 고객 ID, SUM( 출금액 ) 출금액 FROM 출금 GROUP BY 고객 ID) AWHERE NOT EXISTS (SELECT 'X' FROM 입금 WHERE 고객 ID=A. 고객 ID);

SELECT NVL(A. 고객 ID, B. 고객 ID) 고객 ID, A. 입금액 , B. 출금액 FROM (SELECT 고객 ID, SUM( 입금액 ) 입금액 FROM 입금 GROUP BY 고객 ID) A FULL OUTER JOIN (SELECT 고객 ID, SUM( 출금액 ) 출금액 FROM 출금 GROUP BY 고객 ID) B ON A. 고객 ID=B. 고객 ID;

=

Page 62: 효율적인Sql작성방법 4주차

일반 SELECT 문과 전혀 다른 CONNECT BY!!

Page 63: 효율적인Sql작성방법 4주차

순환관계 (CONNECT BY)

ID . . . . P_ID A . . . B . . . A C . . . A D . . . B E . . . B G . . . D F . . . C H . . . F J . . . F

순 환 전 개 법A

B C

D E F

H JG

구조 ( 순환관계 ) 가 변경 되도 식별자는 변하지 않음 잘 못 사용 시 수행속도 저하

1000

1100 1200

1110 1120 1210

1211 12121111

ID . . . . 1000 . . . 1100 . . . 1110 . . . 1111 . . . 1120 . . . 1200 . . . 1210 . . . 1211 . . . 1212 . . .

사용하기가 쉽고 간편하며 수행속도에 상대적으로 유리함 구조 변경에 매우 취약함 ( 식별자 변경 )

구조 변경 시 과거 데이터의 수정이 필요함

C O D E 대 비 법

Page 64: 효율적인Sql작성방법 4주차

순환관계 (CONNECT BY)

CONNECT BY SQL GENERAL SQL

SELECT SELECT LEVELLEVEL , COL1, COL2,......, COL1, COL2,......SEUDO 컬럼

SELECT COL1, COL2,......

JOIN 테이블 FROM TAB1 ( 동일테이블로 조인 간주 ) FROM TAB1 x, TAB2 yFROM TAB1 x, TAB2 y

WHERE conditions . . . . . .WHERE conditions . . . . . .

AND check_conditions . . . . . .CHECK 조건

JOIN 조건 CONNECT BY CONNECT BY PRIORPRIOR ID = P_ID ID = P_ID

and conditions . . . and conditions . . .

WHERE WHERE x.KEY = y.KEYKEY = y.KEY

선처리 테이블조건START WITH conditions

AND driving_table_conditions

선처리테이블 ALIAS

Page 65: 효율적인Sql작성방법 4주차

순환관계 (CONNECT BY) 활용

SELECT LPAD(‘ ‘, 2*LEVEL)||COL1. . . . FROM BOMCONNECT BY PRIOR ID = P_ID AND ID <> ‘F’ START WITH P_ID = ‘A’

특 정 경 우 만 미 추 출예 하 그 룹 미 전 개

SELECT LPAD(‘ ‘, 2*LEVEL)||COL1. . . . FROM BOMWHERE ID <> ‘F’CONNECT BY PRIOR ID = P_IDSTART WITH P_ID = ‘A’

A

C

F

H J

B

D E

G

A

C

F

H J

B

D E

G

Page 66: 효율적인Sql작성방법 4주차

순환관계 (CONNECT BY)

ID . . . . P_ID A . . . B . . . A C . . . A D . . . B E . . . B G . . . D F . . . C H . . . F J . . . F

순 환 전 개 법A

B C

D E F

H JG

최상위 P_ID 는 널로 만들지 않는다 .

최상위에 무의미한 ROW 를 추가해서 효율을 높인다 .

ROOT | NULL | NULL

Page 67: 효율적인Sql작성방법 4주차

순환관계 (CONNECT BY) 활용

SELECT LPAD(‘ ‘, 2*LEVEL)||COL1. . . . FROM BOM CONNECT BY PRIOR ID = P_ID AND T_ID = 1 START WITH P_ID = ‘1000’ AND T_ID = 1

전 체 집 합 순 환 관 계소 그 룹 별 순 환 관 계1000

1100 1200

1110 1120 1210

1211 12121111

T_ID = 11000

1100 1200

1110 1120 1210

1211 12121111

T_ID = 2

1000

1100 1200

1110 1120 1210

1211 12121111

T_ID = 3

A

E F

H JG

1

B2

DF

K

G

C P

H

O

SELECT LPAD(‘ ‘, 2*LEVEL)||COL1. . . . FROM BOMCONNECT BY PRIOR ID1 = P_ID1 AND PRIOR ID2 = P_ID2 START WITH P_ID1 = ‘A’ AND P_ID2 = ‘10’

Page 68: 효율적인Sql작성방법 4주차

시내 주행 1등급 연비 스칼라 서브쿼리 !

Page 69: 효율적인Sql작성방법 4주차

스칼라 서브쿼리

SELECT (SELECT B.NAME FROM DEPT B WHERE B.DEPT_NO = A.EMP_NO) FROM EMP_NO A

출력 값 : B.NAME

입력 값 : A.EMP_NOCache

Page 70: 효율적인Sql작성방법 4주차

스칼라 서브쿼리

SELECT GET_USER_AMT(A.EMP_ID) FROM EMP_NO A, ………

SELECT (SELECT GET_USER_AMT(A.EMP_ID) FROM DUAL) FROM EMP_NO A, ……… 함수 입력 값의 종류가 적을 수록 효율적

캐시 사이즈가 부족하여 해시 충돌이 발생하면 엄청난 부하를 발생 시킴 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

Page 71: 효율적인Sql작성방법 4주차

스칼라 서브쿼리 ( 해시 충돌 제어 방법 )

SELECT (SELECT GET_USER_AMT(A.EMP_ID) FROM DUAL) FROM EMP_NO A, ……… 해시 충돌이 발생하면 기존 엔티리를 밀어내고 새로운 엔트리 생성이 반복되면서 성능부하 발생 !

캐시 사이즈 증가로 해시 충돌 방지 ! ALTER SESSION SET “_query_execution_cache_max_size” = 3000000;

45 초

0.79 초

Page 72: 효율적인Sql작성방법 4주차

ERD

Page 73: 효율적인Sql작성방법 4주차

EXPLAIN PLAN

ID OPERATION OPTIONS OBJECT_NAME1 FILTER 2 NESTED LOOPS 3 TABLE ACCESS FULL EMP 4 TABLE ACCESS BY ROWID DEPT 5 INDEX UNIQUE SCAN PK_DEPT 6 TABLE ACCESS FULL SAL-GRADE

1

2 6

FILTER

NESTEDLOOPS

TABLE ACCESS(FULL) salgrade

3 4

TABLE ACCESS(FULL) emp

TABLE ACCESS(BY ROWID) dept

5INDEX(UNIQUE SCAN)pk_dept

SELECT ename, job, sal, dname FROM emp, deptWHERE emp.deptno = dept.deptnoAND not exists (SELECT 1 FROM salgrade WHERE emp.sal BETWEEN losal AND hisal)

Page 74: 효율적인Sql작성방법 4주차

마무리테스트 어렵지 않다 . 튜닝

개발

VS무엇이 더어려울까요 ?

Page 75: 효율적인Sql작성방법 4주차