이전 글(NULL AWARE ANTI JOIN은 SQL을 어떻게 변경시키나?) 에서 NULL AWARE ANTI JOIN 중에서 조인방법이 NESTED LOOPS 조인을 선택한다면 NULL을 체크하는 서브쿼리가 추가된다고 설명하였다. 이번에는 NESTED LOOPS ANTI NULL AWARE가 아닌 HASH JOIN ANTI NULL AWARE에 대하여 알아보자. 들어가기 전에 이번 글을 이해하려면 이전 글의 이해가 필수적이니 먼저 빠르게 읽고 오기 바란다.
오해를 하다
책(The Logical Optimizer)의 158 페이지의 내용에 따르면 WHERE 조건이 추가되면 NULL을 체크하는 Filter가 적용되지 않는다고 하였다. 하지만 이것은 필자의 오해였다. 얼굴이 화끈거리는 오류이다. 아래의 예제를 보자.
SELECT /*+ QB_NAME(
d.department_id, d.department_name, d.location_id
FROM department d
WHERE d.department_id NOT IN (SELECT /*+ QB_NAME(SUB) */
e.department_id
FROM employee e
WHERE e.job_id = 'PU_CLERK')
AND d.location_id = 1700;
--------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost | Time |
--------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 16 | 512 | 5 | 00:00:01 |
|* 1 | HASH JOIN ANTI NA | | 16 | 512 | 5 | 00:00:01 |
| 2 | TABLE ACCESS BY INDEX ROWID| DEPARTMENT | 21 | 420 | 2 | 00:00:01 |
|* 3 | INDEX RANGE SCAN | DEPT_LOCATION_IX | 21 | | 1 | 00:00:01 |
| 4 | TABLE ACCESS BY INDEX ROWID| EMPLOYEE | 5 | 60 | 2 | 00:00:01 |
|* 5 | INDEX RANGE SCAN | EMP_JOB_IX | 5 | | 1 | 00:00:01 |
--------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("D"."DEPARTMENT_ID"="E"."DEPARTMENT_ID")
3 - access("D"."LOCATION_ID"=1700)
5 - access("E"."JOB_ID"='PU_CLERK')
SELECT /*+ gather_plan_statistics use_hash(e@sub) */
d.department_id, d.department_name, location_id
FROM department d
WHERE d.department_id NOT IN (SELECT /*+ qb_name(sub) */
e.department_id
FROM employee e)
AND d.location_id = 1700;
-----------------------------------------------------------------------------------------
| Id | Operation | Name | A-Rows | A-Time | Buffers |
-----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 0 |00:00:00.01 | 9 |
|* 1 | HASH JOIN ANTI NA | | 0 |00:00:00.01 | 9 |
| 2 | TABLE ACCESS BY INDEX ROWID| DEPARTMENT | 21 |00:00:00.01 | 2 |
|* 3 | INDEX RANGE SCAN | DEPT_LOCATION_IX | 21 |00:00:00.01 | 1 |
| 4 | TABLE ACCESS FULL | EMPLOYEE | 97 |00:00:00.01 | 7 |
-----------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("D"."DEPARTMENT_ID"="E"."DEPARTMENT_ID")
3 - access("D"."LOCATION_ID"=1700)
HASH JOIN ANTI NA는 NULL을 체크하는 NOT EXISTS 서브쿼리를 만들지 않음을 알 수 있다. Predicate Information의 어디에도 NULL을 체크하는 FILTER는 없다. 다시 말하면 HASH JOIN ANTI NA는 IS NULL Filter 서브쿼리를 만들지 않고 Hash 조인을 할 때 NULL 데이터를 체크하므로 NULL 체크용 서브쿼리가 필요 없는 것이다.
결론
Null을 체크하는 서브쿼리는 NESTED LOOP ANTI NA인 경우만 추가되고 HASH JOIN ANTI NA에서는 생성되지 않는다. 필자는 책을 집필할 자료를 준비할 때 데카르트의 방법을 의도적으로 사용하였지만 이렇게 간단한 원리도 놓치고 말았다. 데카르트의 방법론이 어렵고 특별할 것 같지만 사실은 아주 간단하다. 어떤 것을 연구하거나 진리를 탐구할 때 내가 아는 것이 없다고 가정하는 것이다. 즉 내가 아는 것까지 모른다고 가정하고 모든 것을 검증하라는 것이다. 궁금한 사람은 데카르트의 방법서설을 자세히 읽어보라.
'The Logical Optimizer' 카테고리의 다른 글
The Logical Optimizer-Part 3 PPT (5) | 2010.09.15 |
---|---|
Heuristic Query Transformation-PPT (11) | 2010.08.12 |
NULL AWARE ANTI JOIN은 SQL을 어떻게 변경시키나? (2) | 2010.08.02 |
The Logical Optimizer Part 1 - PPT (17) | 2010.07.26 |
The Logical Optimizer-서점 (0) | 2010.04.27 |