연결고리가 없는 두테이블이 먼저 네스티드 조인으로 풀리는 실행계획에 대해...
interlee 수험생

답변 채택시 : 0코아

답변 1 추천 0 조회 1929 2015.12.15

옵티마이져의 원리를 이해하기 위해 연결고리를 일부러 부러뜨리면서 (인덱스 Suppression) 그 실행계획결과를 보고있습니다.
최악의 실행계획을 유도하고자 다음과 같이 룰베이스로 힌트를 주고 또 연결고리의 인덱스를 Suppress 했더니 예상대로 최악의 실행속도를 보여주었습니다.

SELECT /*+ RULE */ f.*
  FROM fact_employee_job_status f, dim_employee e, dim_job j
 WHERE e.emplid = '1054177'
   AND f.employee_sid*1 = e.employee_sid -- 인덱스 Suppress
   AND f.job_sid = j.job_sid
 ORDER BY etl_snapshot_date_sid
;



그런데 문제는 아래의 실행계획을 제가 잘 해석을 할 수 없다는 데 있습니다 (그래픽 버젼도 첨부합니다).
-----------------------------------------------------------------------  
| Id  | Operation                       | Name                        |
-----------------------------------------------------------------------
|   0 | SELECT STATEMENT                |                             |
|   1 |  SORT ORDER BY                  |                             |
|   2 |   NESTED LOOPS                  |                             |
|   3 |    NESTED LOOPS                 |                             |
|   4 |     NESTED LOOPS                |                             |
|   5 |      TABLE ACCESS FULL          | DIM_JOB                     |
|   6 |      TABLE ACCESS BY INDEX ROWID| DIM_EMPLOYEE                |
|*  7 |       INDEX RANGE SCAN          | UI_DIM_EMPLOYEE_BK          |
|*  8 |     INDEX RANGE SCAN            | IX_FACT_EMPLOYEE_JOB_STATUS |
|   9 |    TABLE ACCESS BY INDEX ROWID  | FACT_EMPLOYEE_JOB_STATUS    |
-----------------------------------------------------------------------
                                                                      
Predicate Information (identified by operation id):                  
---------------------------------------------------                 
                                                                   
   7 - access("E"."EMPLID"='1054177')                             
   8 - access("F"."JOB_SID"="J"."JOB_SID")                       
       filter("E"."EMPLOYEE_SID"="F"."EMPLOYEE_SID"*1)

즉, 5번 6번을 보면 dim_job이 풀스캔한후 dim_employee를 네스티드로 엑세스 하는데 두 테이블이 직접적인 연결고리가 아닌데 이 상황이 가능한지 이해가 되지 않네요. 설마 카테션 조인이 되는 걸 의미하나요?


혹시 왜 이런 짓을 하냐고 물으시면, 처음에 말씀드렸듯이, 옵티마이져의 행동양식을 "열공"중에 바보같은 퀴어리를 만들었을 때 옵티마이져의 반응이 궁금해서 해보았습니다. 여기에서 제가 궁금한 것은 어떻게 최적화된 퀴어리를 만드느냐가 아니라, 단순히 옵티마이져가 만든 실행계획이 잘 "해석"이 안된다는 것입니다.


두 테이블 모두 DW환경에서 Dimension 테이블이고 Fact 테이블(fact_employee_job_status)에서 Foreign Key (_SID)로 연결되기에 두 Dimension테이블 간에는 직접적인 연결고리가 없거든요.

참고로 각 테이블의 레코드수는 대략 다음과 같습니다.

fact_employee_job_status: 25,000,000
dim_employee: 1,000,000
dim_job: 1,400,000

고수님들의 한수 부탁드립니다.

댓글 (0)
목록 답변등록
연결고리가 없는 두테이블이 먼저 네스티드 조인으로 풀리는 실행계획에 대해...
salinokl 2015.12.16

질문자로부터 답변이 채택 되었습니다.

안녕하세요,


실행 계획 중 access 조건을 보시면, 

7 - access("E"."EMPLID"='1054177') 

가 있습니다.


즉, 아래와 같이 동작합니다.

1. DIM_JOB 테이블을 풀 스캔

2. DIM_JOB 테이블의 각 레코드 마다, DIM_EMPLOYEE 테이블에서 EMPLID가 '1054177'인 레코드를 몽땅 연결


pseudo 코드로 작성하면 아래와 같습니다


[DIM_JOB의 각 레코드 record_j 마다]

{

    [UI_DIM_EMPLOYEE_BK 에서 emplid 가 '1054177' 인 각 레코드 record_eidx 마다]

    {

        record_e = [record_eidx의 INDEX ROWID로 DIM_EMPLOYEE 테이블에 access];

        record_j 와 record_e 조인;

    }

}


말씀하신 대로, 연결고리가 없으니 조건부 cartesian 조인의 형태가 됩니다.


사실 정확히 말하자면, E.EMPLID = '1054177'가 연결고리가 됩니다.

연결 고리를 정의하자면, '두 레코드간 조인이 수행되는 조건'입니다.

한쪽 레코드의 조건만 지정했으니, 다른 쪽 레코드는 항상 조인에 참여하게 되는 것입니다.

댓글 (0)