SQL> create index emp_deptno_idx on emp(deptno);
인덱스가 생성되었습니다.
SQL> set autotrace traceonly explain
SQL> select * from emp where deptno = 20;
Execution Plan
----------------------------------------------------------
Plan hash value: 2468466201
----------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 5 | 190 | 2 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| EMP | 5 | 190 | 2 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | EMP_DEPTNO_IDX | 5 | | 1 (0)| 00:00:01 |
----------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("DEPTNO"=20)
SQL> create index emp_idx on emp(ename, sal);
인덱스가 생성되었습니다.
SQL> set autotrace traceonly exp
SQL> select * from emp
2 where sal > 2000
3 order by ename;
Execution Plan
----------------------------------------------------------
Plan hash value: 737262432
---------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 10 | 370 | 2 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| EMP | 10 | 370 | 2 (0)| 00:00:01 |
|* 2 | INDEX FULL SCAN | EMP_IDX | 10 | | 1 (0)| 00:00:01 |
---------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("SAL">2000)
filter("SAL">2000)
Execution Plan
Id | Operation | Name | Rows | Bytes | Cost (%CPU) | Time |
0 | SELECT STATEMENT | 1 | 37 | 2 (0) | 00:00:01 | |
1 | TABLE ACCESS BY INDEX ROWID | EMP | 1 | 37 | 2 (0) | 00:00:01 |
| INDEX FULL SCAN | EMP_IDX | 1 | 1 (0) | 00:00:01 |
Predicate Information (identified by operation id):
** 연봉이 5,000을 초과하는 사원이 전체 중 극히 일부라면 Table Full Scan 보다는 Index Full Scan을 통한 필터링이 큰 효과를 가져다준다.
* h5. 인덱스를 이용한 소트 연산 대체 : first_rows 힌트
** 전체 집합 중 처음 일부만을 빠르게 리턴해야하므로 옵티마이저는 전략적으로 Index Full Scan 수행
** 만약 결과 집합이 많을 경우 데이터 읽기를 멈추지 않고 끝까지 fetch한다면 인덱스 스캔이 테이블 스캔보다 불리 : 많은 I/O를 일으키면서 서버 자원을 낭비 초래
h3. (3) Index Unique Scan
!img_3_03.png!
* 수직적 탐색만으로 데이터를 찾는 스캔 방식이다.
* 인덱스를 통해 '=' 조건으로 탐색하는 경우에 작동한다.
* Unique 인덱스가 존재하는 컬럼은 중복 값이 발생하지 않도록 DBMS가 정합성을 관리해 준다.
{code:sql}
SQL> select empno, ename from emp where empno = 7788;
Execution Plan
----------------------------------------------------------
Plan hash value: 2949544139
--------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 10 | 1 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 10 | 1 (0)| 00:00:01 |
|* 2 | INDEX UNIQUE SCAN | PK_EMP | 1 | | 0 (0)| 00:00:01 |
--------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("EMPNO"=7788)
Index Full Scan | Index Fast Full Scan |
---|---|
1. 인덱스 구조를 따랄 스캔 2. 결과 집합 순서 보장 3. Single Block I/O 4. 병렬스캔 불가(파티션 되어 있지 않을 경우) 5. 인덱스에 포함되지 않은 컬럼 조회 시에도 사용 가능 | 1. 세그먼트 전체를 스캔 2. 결과집합 순서 보장 안 됨 3. multiblock I/O 4. 병렬스캔 가능 5. 인덱스에 포함된 컬럼으로만 조회할 때 사용 가능 |
set autotrace traceonly explain
select /*+ and_equal(e emp_deptno_idx emp_job_idx) */ * from emp e where deptno=30 and job='SALESMAN';
Execution Plan
----------------------------------------------------------
Plan hash value: 2839249562
----------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 32 | 3 (0)| 00:00:01 |
|* 1 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 32 | 3 (0)| 00:00:01 |
| 2 | AND-EQUAL | | | | | |
|* 3 | INDEX RANGE SCAN | EMP_JOB_IDX | 3 | | 1 (0)| 00:00:01 |
|* 4 | INDEX RANGE SCAN | EMP_DEPTNO_IDX | 5 | | 1 (0)| 00:00:01 |
----------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("JOB"='SALESMAN' AND "DEPTNO"=30)
3 - access("JOB"='SALESMAN')
4 - access("DEPTNO"=30)
set autotrace traceonly explain
select /*+ index_combine(e emp_deptno_idx emp_job_idx) */ * from emp e where deptno=30 and job='SALESMAN';
Execution Plan
----------------------------------------------------------
Plan hash value: 2413831903
---------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 32 | 4 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID | EMP | 1 | 32 | 4 (0)| 00:00:01 |
| 2 | BITMAP CONVERSION TO ROWIDS | | | | | |
| 3 | BITMAP AND | | | | | |
| 4 | BITMAP CONVERSION FROM ROWIDS| | | | | |
|* 5 | INDEX RANGE SCAN | EMP_JOB_IDX | | | 1 (0)| 00:00:01 |
| 6 | BITMAP CONVERSION FROM ROWIDS| | | | | |
|* 7 | INDEX RANGE SCAN | EMP_DEPTNO_IDX | | | 1 (0)| 00:00:01 |
---------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
5 - access("JOB"='SALESMAN')
7 - access("DEPTNO"=30)
1단계 : 일반 B*Tree 인덱스를 스캔하면서 각 조건에 만족하는 레코드의 rowid 목록 얻기(INDEX RANGE SCAN)
2단계 : 1단계에서 얻은 rowid목록을 가지고 비트맵 인덱스 구조 만들기(BITMAP CONVERSION FROM ROWIDS)
3단계 : 비트맵 인덱스에 대한 bit-wise operation 수행(BITMAP AND)
4단계 : bit-wise operation 수행 결과가 true인 비트 값들을 rowid 값으로 환산해 최종적으로 방문할 테이블 rowid 목록 얻기(BITMAP CONVERSION TO ROWIDS)
5단계 : rowid를 이용해 테이블 액세스(TABLE ACCESS BY INDEX ROWID)
set autotrace traceonly explain
select /*+ index_join(e emp_deptno_idx emp_job_idx) */ * from emp e where deptno=30 and job='SALESMAN';
Execution Plan
----------------------------------------------------------
Plan hash value: 2211876416
-------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 32 | 2 (0)| 00:00:01 |
|* 1 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 32 | 2 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | EMP_JOB_IDX | 3 | | 1 (0)| 00:00:01 |
-------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("DEPTNO"=30)
2 - access("JOB"='SALESMAN')
set autotrace traceonly explain
select /*+ index_join(e emp_deptno_idx emp_job_idx) */ deptno,job from emp e where deptno=30 and job='SALESMAN';
Execution Plan
----------------------------------------------------------
Plan hash value: 3557895725
---------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 9 | 3 (34)| 00:00:01 |
|* 1 | VIEW | index$_join$_001 | 1 | 9 | 3 (34)| 00:00:01 |
|* 2 | HASH JOIN | | | | | |
|* 3 | INDEX RANGE SCAN| EMP_JOB_IDX | 1 | 9 | 1 (0)| 00:00:01 |
|* 4 | INDEX RANGE SCAN| EMP_DEPTNO_IDX | 1 | 9 | 1 (0)| 00:00:01 |
---------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("JOB"='SALESMAN' AND "DEPTNO"=30)
2 - access(ROWID=ROWID)
3 - access("JOB"='SALESMAN')
4 - access("DEPTNO"=30)
1단계 : 크기가 비교적 작은 쪽 인덱스(emp_job_idx)에서 키 값과 rowid를 얻어 PGA 메모리에 해시 맵 생성
(해시 키 = rowid 가 사용)
2단계 : 다른 쪽 인덱스(emp_dept_idx)를 스캔하면서 먼저 생성한 해시 맵에 같은 rowid 값을 갖는 레코드가 있는지 탐색
3단계 : rowid끼리 조인에 성공한 레코드만 결과집합에 포함 : 이 rowid가 가리키는 테이블은 각 인덱스 컬럼에 대한 검색 조건을 모두 만족한다