(오라클sql무료 온라인화상교육강좌)2회차 강의자료,복합인덱스와 index힌트...

14
온라인 화상(양방향) 교육 2회차 (2016.12.15 목요일 20:30~21:00) - 복합인덱스 스캐닝과 관련된 힌트구문 - INDEX JOIN개요 및 관련힌트구문

Upload: 3-2

Post on 16-Apr-2017

905 views

Category:

Education


0 download

TRANSCRIPT

Page 1: (오라클SQL무료 온라인화상교육강좌)2회차 강의자료,복합인덱스와 INDEX힌트 구문, INDEX JOIN개요 및 INDEX_JOIN 힌트소개 간단한 이론 및 실습_SQL튜닝교육추천

온라인 화상(양방향) 교육 2회차

(2016.12.15 목요일 20:30~21:00)

- 복합인덱스 스캐닝과 관련된 힌트구문

- INDEX JOIN개요 및 관련힌트구문

Page 2: (오라클SQL무료 온라인화상교육강좌)2회차 강의자료,복합인덱스와 INDEX힌트 구문, INDEX JOIN개요 및 INDEX_JOIN 힌트소개 간단한 이론 및 실습_SQL튜닝교육추천

INDEX 힌트와 복합인덱스

인자로 INDEX 힌트에 인덱스명이 아닌 칼럼이 출현하면 해당 칼럼을

포함하고 있는 인덱스를 이용하라는 의미이다.

[형식]

/*+ INDEX(테이블명 (칼럼명, 칼럼명,,,)) */

-- 실습 테이블 생성

SQL> CREATE TABLE INDEXTEST (

A1 NUMBER NOT NULL,

A2 NUMBER NOT NULL,

A3 VARCHAR2(50) NOT NULL,

A4 VARCHAR2(100));

-- 100만건 생성

SQL> INSERT INTO INDEXTEST

SELECT

MOD(ROWNUM-1, 90) * 4 A1,

ROWNUM - 1 A2,

TO_CHAR(ROWNUM - 1, 'RN') A3,

LPAD('A',100,'A') A4

FROM

DUAL

CONNECT BY

LEVEL<=1000000;

SQL> COMMIT;

-- 실습을 위한 인덱스 생성

Page 3: (오라클SQL무료 온라인화상교육강좌)2회차 강의자료,복합인덱스와 INDEX힌트 구문, INDEX JOIN개요 및 INDEX_JOIN 힌트소개 간단한 이론 및 실습_SQL튜닝교육추천

SQL> CREATE INDEX IDX_IT_1_2 ON INDEXTEST(A1,A2);

SQL> CREATE INDEX IDX_IT_2_1_3 ON INDEXTEST(A2,A1,A3);

SQL> CREATE INDEX IDX_IT_3_1_2 ON INDEXTEST(A3,A1,A2);

-- INDEXTEST 테이블의 통계정보 생성

SQL> EXEC

DBMS_STATS.GATHER_TABLE_STATS(OWNNAME=>USER,TABNAME=>'INDEXTEST',

CASCADE=>TRUE);

-- 먼저 힌트를 사용하지 않은 쿼리를 보자.

-- Full TableScan을 하지않고 A2, A1, A3 복합 인덱스를 사용한다.

SQL> SELECT A1, A2, A3 FROM INDEXTEST

-------------------------------------------------------------------------------------

| Id | Operation | Name | Rows | Bytes | Cost (%CPU)|

Time |

-------------------------------------------------------------------------------------

| 0 | SELECT STATEMENT | | 1000K| 23M| 1336 (1)|

00:00:17 |

| 1 | INDEX FAST FULL SCAN| IDX_IT_2_1_3 | 1000K| 23M| 1336 (1)|

00:00:17 |

-------------------------------------------------------------------------------------

-- 이번에는 A1, A2 칼럼에 있는 인덱스를 사용하라는 힌트를 줘보자.

-- A1, A2 복합인덱스를 이용한다.

SQL> SELECT /*+ index(INDEXTEST (A1, A2)) */ A1, A2, A3 FROM INDEXTEST;

------------------------------------------------------------------------------------------

| Id | Operation | Name | Rows | Bytes | Cost (%CPU)|

Time |

------------------------------------------------------------------------------------------

| 0 | SELECT STATEMENT | | 1000K| 23M| 1003K

(1)| 03:20:40 |

Page 4: (오라클SQL무료 온라인화상교육강좌)2회차 강의자료,복합인덱스와 INDEX힌트 구문, INDEX JOIN개요 및 INDEX_JOIN 힌트소개 간단한 이론 및 실습_SQL튜닝교육추천

| 1 | TABLE ACCESS BY INDEX ROWID| INDEXTEST | 1000K| 23M|

1003K (1)| 03:20:40 |

| 2 | INDEX FULL SCAN | IDX_IT_1_2 | 1000K| | 2755 (1)|

00:00:34 |

------------------------------------------------------------------------------------------

-- 이번엔 A2, A1 칼럼 인덱스를 사용하라는 힌트를 줘보자.

SQL> SELECT /*+ index(INDEXTEST (A2, A1)) */ A1, A2, A3 FROM INDEXTEST;

---------------------------------------------------------------------------------

| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time

|

---------------------------------------------------------------------------------

| 0 | SELECT STATEMENT | | 1000K| 23M| 4905 (1)|

00:00:59 |

| 1 | INDEX FULL SCAN | IDX_IT_2_1_3 | 1000K| 23M| 4905 (1)| 00:00:59

|

---------------------------------------------------------------------------------

힌트를 사용하지 않은 쿼리보다 COST가 더 높게 나온다.

-- 이번엔 A3, A1, A2 칼럼 인덱스를 사용하라는 힌트를 줘보자.

-- A3, A1, A2 복합인덱스를 이용한다.

SQL> SELECT /*+ index(INDEXTEST (A3, A1, A2)) */ A1, A2, A3 FROM INDEXTEST;

---------------------------------------------------------------------------------

| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time

|

---------------------------------------------------------------------------------

| 0 | SELECT STATEMENT | | 1000K| 23M| 5188 (1)|

00:01:03 |

| 1 | INDEX FULL SCAN | IDX_IT_3_1_2 | 1000K| 23M| 5188 (1)| 00:01:03

Page 5: (오라클SQL무료 온라인화상교육강좌)2회차 강의자료,복합인덱스와 INDEX힌트 구문, INDEX JOIN개요 및 INDEX_JOIN 힌트소개 간단한 이론 및 실습_SQL튜닝교육추천

|

---------------------------------------------------------------------------------

-- 이번에는 A1, A2 칼럼 인덱스를 사용하는데 A2 칼럼에 조건을 줘보자.

-- 힌트구안에 A1, A2가 기술되어 있으므로 IDX_IT_1_2 인덱스를 이용하여

-- A1칼럼을 SKIP하면서 A2조건을 확인하는 Index skip Scanning 연산을 한다.

SQL> SELECT /*+ index(INDEXTEST (A1, A2)) */ A1, A2, A3 FROM INDEXTEST

WHERE A2 < 10;

------------------------------------------------------------------------------------------

| Id | Operation | Name | Rows | Bytes | Cost (%CPU)|

Time |

------------------------------------------------------------------------------------------

| 0 | SELECT STATEMENT | | 10 | 250 | 103 (0)|

00:00:02 |

| 1 | TABLE ACCESS BY INDEX ROWID| INDEXTEST | 10 | 250 | 103 (0)|

00:00:02 |

|* 2 | INDEX SKIP SCAN | IDX_IT_1_2 | 10 | | 92 (0)|

00:00:02 |

------------------------------------------------------------------------------------------

-- 앞 예문에서 A1, A2의 순서만 바꾸면 IDX_IT_2_1_3을 이용하여

-- INDEX RANGE SCAN 한다.

SQL> SELECT /*+ index(INDEXTEST (A2, A1)) */ A1, A2, A3

FROM INDEXTEST

WHERE A2 < 10;

-- 이번엔 A1, A2, A3 칼럼의 인덱스를 사용하라는 힌트를 줘보자.

-- IDX_IT_1_2 인덱스에는 A3 칼럼이 없으므로 사용하지 않고, WHERE절에 A2칼

럼이 출현했으므로 IDX_IT_2_1_3 인덱스를 사용했다.

SQL> SELECT /*+ index(INDEXTEST (A1, A2, A3)) */ A1, A2, A3 FROM INDEXTEST

Page 6: (오라클SQL무료 온라인화상교육강좌)2회차 강의자료,복합인덱스와 INDEX힌트 구문, INDEX JOIN개요 및 INDEX_JOIN 힌트소개 간단한 이론 및 실습_SQL튜닝교육추천

WHERE A2 < 10;

---------------------------------------------------------------------------------

| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time

|

---------------------------------------------------------------------------------

| 0 | SELECT STATEMENT | | 10 | 250 | 3 (0)| 00:00:01 |

|* 1 | INDEX RANGE SCAN| IDX_IT_2_1_3 | 10 | 250 | 3 (0)| 00:00:01 |

---------------------------------------------------------------------------------

-- A1, A2, A3순으로 인덱스를 생성하자.

-- A2 칼럼으로 WHERE절에 비교했지만 A3칼럼이 SELECT 리스트에 있고

IDX_IT_1_2_3인덱스가

-- 있으므로 이 인덱스를 이용하여 SKIP SCANNING 한다.

SQL> CREATE INDEX IDX_IT_1_2_3 ON INDEXTEST(A1,A2,A3);

-- A1, A2, A3 순서대로 생성된 IDX_IT_1_2_3 인덱스가 있고

-- A2 칼럼으로 WHERE절에 비교했으므로 IDX_IT_1_2_3인덱스 이용하여 SKIP

SCANNING

-- 만약 IDX_IT_1_2_3 인덱스가 없다면 IDX_IT_2_1_3 인덱스를 이용할 것이다.

SQL> SELECT /*+ INDEX(INDEXTEST (A1 A2 A3)) */ A1,A2,A3 FROM INDEXTEST

WHERE A2 < 10; ------------------------------------------------------------------------

---------

| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time

|

---------------------------------------------------------------------------------

| 0 | SELECT STATEMENT | | 10 | 250 | 92 (0)| 00:00:02 |

|* 1 | INDEX SKIP SCAN | IDX_IT_1_2_3 | 10 | 250 | 92 (0)| 00:00:02 |

---------------------------------------------------------------------------------

-- 아래의 경우 A1, A2 칼럼의 인덱스를 쓰라는 힌트인데

-- A3 칼럼 때문에 TABLE ACCESS(BY INDEX ROWID)연산을 한다.

Page 7: (오라클SQL무료 온라인화상교육강좌)2회차 강의자료,복합인덱스와 INDEX힌트 구문, INDEX JOIN개요 및 INDEX_JOIN 힌트소개 간단한 이론 및 실습_SQL튜닝교육추천

SQL> SELECT /*+ INDEX(INDEXTEST (A1 A2)) */ A1,A2,A3 FROM INDEXTEST

WHERE A2 < 10;

------------------------------------------------------------------------------------------

| Id | Operation | Name | Rows | Bytes | Cost (%CPU)|

Time |

------------------------------------------------------------------------------------------

| 0 | SELECT STATEMENT | | 10 | 250 | 103 (0)|

00:00:02 |

| 1 | TABLE ACCESS BY INDEX ROWID| INDEXTEST | 10 | 250 | 103 (0)|

00:00:02 |

|* 2 | INDEX SKIP SCAN | IDX_IT_1_2 | 10 | | 92 (0)|

00:00:02 |

------------------------------------------------------------------------------------------

-- 아래의 경우 A1 칼럼의 인덱스를 쓰라는 힌트인데

-- WHERE절에 A2 칼럼이 출현했으므로 가능하면 A1이 선두칼럼에 있는 인덱스

를 선택할 것이고, A3 칼럼이 SELECT 리스트에 출현했으므로 IDX_IT_1_2_3 인덱

스를 사용한다.

SQL> SELECT /*+ INDEX(INDEXTEST (A1)) */ A1,A2,A3 FROM INDEXTEST

WHERE A2 < 10;

---------------------------------------------------------------------------------

| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time

|

---------------------------------------------------------------------------------

| 0 | SELECT STATEMENT | | 10 | 250 | 92 (0)| 00:00:02 |

|* 1 | INDEX SKIP SCAN | IDX_IT_1_2_3 | 10 | 250 | 92 (0)| 00:00:02 |

---------------------------------------------------------------------------------

----------------------------------------------------------------------------------

-- myemp1(1000 만건) 이용한 실습

Page 8: (오라클SQL무료 온라인화상교육강좌)2회차 강의자료,복합인덱스와 INDEX힌트 구문, INDEX JOIN개요 및 INDEX_JOIN 힌트소개 간단한 이론 및 실습_SQL튜닝교육추천

----------------------------------------------------------------------------------

-- deptno, job, sal를 이용한 복합 인덱스 생성

create index idx_myemp1_deptno_job_sal on myemp1(deptno, job, sal);

-- idx_myemp1_deptno_job_sal 인덱스이용 INDEX FULL SCAN 한다.

-- 0.6초

select /*+ index(myemp1 (deptno, job)) */ count(1)

from myemp1

where job = 'CLERK';

-- idx_myemp1_deptno_job_sal 인덱스이용 INDEX FULL SCAN 한다.

-- 0.4초, 위의 실행계획보다는 조금 이점이 있다.

select /*+ index_ss(myemp1 (deptno, job)) */ count(1)

from myemp1

where job = 'CLERK';

-- idx_myemp1_job_deptno_sal 인덱스이용 INDEX RANGE SCAN 한다.

-- 0.06초, 최적의 방법

select /*+ index(myemp1 ( job, deptno)) */ count(1)

from myemp1

where job = 'CLERK';

-- 힌트 사용안했더니 idx_myemp1_deptno_job_sal 인덱스 이용 FAST FULL

SCAN 한다.

-- 0.9초

select count(1)

from myemp1

where job in ('CLERK', 'SALESMAN')

and sal > 10000

and deptno not in ('1');

-- INDEX SKIP SCAN을 유도, 3초

Page 9: (오라클SQL무료 온라인화상교육강좌)2회차 강의자료,복합인덱스와 INDEX힌트 구문, INDEX JOIN개요 및 INDEX_JOIN 힌트소개 간단한 이론 및 실습_SQL튜닝교육추천

select /*+ index_ss(myemp1 (deptno)) */ count(1)

from myemp1

where job in ('CLERK', 'SALESMAN')

and sal > 10000

and deptno not in ('1');

-- 부서코드로 내림차순 정렬, FULL TABLE SCAN 한다. 1.6초

select ename, deptno, job

from myemp1

where job in ('CLERK', 'SALESMAN')

and sal > 10000

and deptno not in ('0')

order by deptno desc;

-- 인덱스 영역에서 뒤쪽부터 스캐닝하면 된다. 0.2초

select /*+ index_desc(myemp1 (deptno)) */ ename, deptno, job

from myemp1

where job in ('CLERK', 'SALESMAN')

and sal > 10000

and deptno not in ('0');

-- 인덱스 스킵 스캔을 인덱스 뒷부분 부터 해보자. 0.5초

select /*+ index_ss_desc(myemp1 (deptno)) */ ename, deptno, job

from myemp1

where job in ('CLERK', 'SALESMAN')

and sal > 10000

and deptno not in ('0');

Page 10: (오라클SQL무료 온라인화상교육강좌)2회차 강의자료,복합인덱스와 INDEX힌트 구문, INDEX JOIN개요 및 INDEX_JOIN 힌트소개 간단한 이론 및 실습_SQL튜닝교육추천

Hints For Access Paths(INDEX_JOIN)

인덱스를 조인하여 스캐닝을 유도하는 힌트로 효과적이기 위해서는 테이블에

만들어진 인덱스가 SELECT문장 리스트에 나타난 컬럼 들을 모두 가져야

한다. 테이블간 조인에 사용되는 것과 무관하게 하나의 테이블에 있는 여러

인덱스를 이용해 테이블 원본데이터 ACCESS없이 결과 집합을 만들 때

사용하는 인덱스 스캔방식 이다.

내부적으로 해시조인을 이용하며 index$_join$_xxx 의 형태로 실행계획에

표시된다.

MYEMP1 테이블의 인덱스는 PK(empno)외 SAL칼럼에 인덱스가 생성되어 있어

야 한다.

아래 쿼리로 MYEMP1 테이블의 인덱스를 확인해 보고 없다면 SAL 칼럼에 인덱

스를 생성하자.

SQL> SELECT a.index_name, a.column_name, b.visibility

FROM user_ind_columns a, user_indexes b

WHERE a.table_name = 'MYEMP1'

AND a.index_name = b.index_name

PK Unique인덱스의 이름은 PK_MYEMP1 이다.

SQL> DESC MYEMP1

이름 널? 유형

----------------------------------------------------------------------- -------- ----------

---

EMPNO NOT NULL

NUMBER

ENAME

VARCHAR2(100)

Page 11: (오라클SQL무료 온라인화상교육강좌)2회차 강의자료,복합인덱스와 INDEX힌트 구문, INDEX JOIN개요 및 INDEX_JOIN 힌트소개 간단한 이론 및 실습_SQL튜닝교육추천

DEPTNO

VARCHAR2(1)

ADDR

VARCHAR2(100)

SAL

NUMBER(7)

JOB

VARCHAR2(20)

COMM

NUMBER(7)

SUNGBYU

VARCHAR2(1)

HIREDATE DATE

OUTDATE

VARCHAR2(8)

MGR

NUMBER

-- SAL칼럼에 인덱스가 없다면 생성하자.

SQL> create index idx_myemp1_sal on myemp1(sal);

-- 힌트없이 실행하니 전체 테이블을 FULL SCAN 한다. 7.8초

-- MYEMP1 테이블의 EMPNO인 경우 1부터 10,000,002까지 유일한 값을 가지

고 있고

-- sal의 경우 0부터 5,999,999까지의 값으로 이루어져 있다.

-- 1000만건이니 sal 값은 대략 2~3개 정도 중복되어 있다.

SQL> SELECT empno, sal FROM myemp1 e

WHERE e.empno > 8500000

AND e.sal > 1000000

ORDER BY empno DESC;

경 과: 00:00:7.8

Page 12: (오라클SQL무료 온라인화상교육강좌)2회차 강의자료,복합인덱스와 INDEX힌트 구문, INDEX JOIN개요 및 INDEX_JOIN 힌트소개 간단한 이론 및 실습_SQL튜닝교육추천

Execution Plan

-----------------------------------------------------------------------------

| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |

-----------------------------------------------------------------------------

| 0 | SELECT STATEMENT | | 1 | 12 | 25258 (1)| 00:05:04 |

| 1 | SORT AGGREGATE | | 1 | 12 | |

|

|* 2 | TABLE ACCESS FULL| MYEMP1 | 1220K| 13M| 25258 (1)| 00:05:04

|

-----------------------------------------------------------------------------

-- 이번에는 index_join 힌트를 사용해 보자. 2.9초

SQL> SELECT /*+ index_join(e idx_myemp1_sal PK_MYEMP1) */

empno, sal

FROM myemp1 e

WHERE e.empno > 8500000

AND e.sal > 1000000

ORDER BY empno DESC;

경 과: 00:00:02.9

Execution Plan

----------------------------------------------------------------------------------------

| Id | Operation | Name | Rows | Bytes | Cost (%CPU)|

T i m e |

----------------------------------------------------------------------------------------

| 0 | SELECT STATEMENT | | 1 | 12 | 28951 (1)|

0 0 : 0 5 : 4 8 |

| 1 | SORT ORDER BY | | 1 | 12 | |

|

Page 13: (오라클SQL무료 온라인화상교육강좌)2회차 강의자료,복합인덱스와 INDEX힌트 구문, INDEX JOIN개요 및 INDEX_JOIN 힌트소개 간단한 이론 및 실습_SQL튜닝교육추천

|* 2 | VIEW | index$_join$_001 | 1220K| 13M| 28951 (1)|

0 0 : 0 5 : 4 8 |

|* 3 | HASH JOIN | | | | |

|

|* 4 | INDEX RANGE SCAN| PK_MYEMP1 | 1220K| 13M|

4 6 8 9 4 ( 1 ) | 0 0 : 0 9 : 2 3

|* 5 | INDEX RANGE SCAN| IDX_MYEMP1_SAL | 1220K| 13M|

4 3 5 K ( 5 ) |

----------------------------------------------------------------------------------------

-- SELECT 리스트에 인덱스에 없는 컬럼을 기술하니 FULL TABLE SCAN 한다.

SQL> SELECT /*+ index_join(e idx_myemp1_sal PK_MYEMP1) */

empno, sal, sungbyul

FROM myemp1 e

WHERE e.empno > 8500000

AND e.sal > 1000000

ORDER BY empno DESC;

경 과: 00:00:7.99

Execution Plan

-----------------------------------------------------------------------------

| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |

-----------------------------------------------------------------------------

| 0 | SELECT STATEMENT | | 1 | 26 | 25258 (1)| 00:05:04 |

| 1 | SORT AGGREGATE | | 1 | 26 | |

|

|* 2 | TABLE ACCESS FULL| MYEMP1 | 1220K| 30M| 25258 (1)| 00:05:04

|

-----------------------------------------------------------------------------

Page 14: (오라클SQL무료 온라인화상교육강좌)2회차 강의자료,복합인덱스와 INDEX힌트 구문, INDEX JOIN개요 및 INDEX_JOIN 힌트소개 간단한 이론 및 실습_SQL튜닝교육추천