INDEX UNIQUE SCAN의 비밀
당신은 INDEX UNIQUE SCAN을 쉬운 Operation쯤으로 여길 것이다. 하지만 여기에는 숨겨진 기능이 있다. 대표적인 경우가 Unique 인덱스를 사용하여 INDEX UNIQUE SCAN Operation이 나오면 Distinct를 제거하는 기능이다. 이 기능의 이름이 없으므로 DEUI*(Distinct Elimination using Unique Index)라 부르기로 하자. 이제 아래의 SQL을 보자.
SELECT DISTINCT d.department_id, l.city, l.country_id
FROM department d, location l
WHERE d.location_id = l.location_id
AND d.department_id = 10 ;
--------------------------------------------------+-----------------------------------+
| Id | Operation | Name | Rows | Bytes | Cost | Time |
--------------------------------------------------+-----------------------------------+
| 0 | SELECT STATEMENT | | | | 3 | |
| 1 | NESTED LOOPS | | 1 | 22 | 2 | 00:00:01 |
| 2 | TABLE ACCESS BY INDEX ROWID | DEPARTMENT| 1 | 7 | 1 | 00:00:01 |
| 3 | INDEX UNIQUE SCAN | DEPT_ID_PK| 1 | | 0 | |
| 4 | TABLE ACCESS BY INDEX ROWID | LOCATION | 23 | 345 | 1 | 00:00:01 |
| 5 | INDEX UNIQUE SCAN | LOC_ID_PK | 1 | | 0 | |
--------------------------------------------------+-----------------------------------+
Predicate Information:
----------------------
3 - access("D"."DEPARTMENT_ID"=10)
5 - access("D"."LOCATION_ID"="L"."LOCATION_ID")
SQL이 변경되었다
Distinct에 의한 Sort Unique 혹은 Hash Unique가 사라졌다. 그 이유는 테이블 department와 location에서 모두 INDEX UNIQUE SCAN을 사용하였기 때문이다. 하지만 반대로 Unique 인덱스를 사용하지 않는다면 DEUI는 절대 수행되지 않는다. 아래의 SQL은 위의 SQL에서 힌트만 추가한 것이다.
SELECT /*+ FULL(d) */ DISTINCT d.department_id, l.city, l.country_id
FROM department d, location l
WHERE d.location_id = l.location_id
AND d.department_id = 10 ;
---------------------------------------------------+-----------------------------------+
| Id | Operation | Name | Rows | Bytes | Cost | Time |
---------------------------------------------------+-----------------------------------+
| 0 | SELECT STATEMENT | | | | 5 | |
| 1 | HASH UNIQUE | | 1 | 22 | 5 | 00:00:01 |
| 2 | NESTED LOOPS | | | | | |
| 3 | NESTED LOOPS | | 1 | 22 | 4 | 00:00:01 |
| 4 | TABLE ACCESS FULL | DEPARTMENT| 1 | 7 | 3 | 00:00:01 |
| 5 | INDEX UNIQUE SCAN | LOC_ID_PK | 1 | | 0 | |
| 6 | TABLE ACCESS BY INDEX ROWID | LOCATION | 23 | 345 | 1 | 00:00:01 |
---------------------------------------------------+-----------------------------------+
Predicate Information:
----------------------
4 - filter("D"."DEPARTMENT_ID"=10)
5 - access("D"."LOCATION_ID"="L"."LOCATION_ID")
순간의 실수로
Department 테이블을 Full Scan 하자 Plan 상에 HASH UNIQUE가 나타났다. 다시 말해서 옵티마이져의 실수로 다른 종류의 인덱스를 사용하거나 Full Scan이 된다면 Query Transformation은 발생되지 않는다.
결론
다음시간에는 DEUI의 사촌격인 DE에 대하여 논의하자.
이번 내용도 집필중인 책의 일부분이다. 이제 어떤 것을 주제로 한 책인지 감이 오지 않는가?
'Oracle > Optimizer' 카테고리의 다른 글
해결사 되기 (15) | 2010.02.04 |
---|---|
Distinct Elimination : 불필요한 Distinct를 제거하라 (6) | 2010.01.25 |
내가 사용한 Hint 가 무시되는 이유 (10) | 2010.01.04 |
Interleaving : CBQT중에는 선수조건이 필요한 경우가 있다 (14) | 2009.12.07 |
MERGE 문과 IN 조건이 만난다면 (8) | 2009.11.26 |