Optimizing Oracle Optimizer (2011년)
10053 Event 0 0 2,620

by 구루비스터디 10053 Event [2018.07.14]


10053 Event의 출력 결과

  • CBO가 참조하는 기본 환경( Optimizer와 관련된 Parameter 및 Bug Fix Patch(?) )
  • Query Transformation 과정( 복잡한 SQL문장이 어떻게 Transformation되는지, 혹은 왜 Transformation에 실패하는지에 대한 정보 )
  • Query Optimization 과정( System 및 Object Statistics를 참조하는 일련의 과정과 Access Type의 결정, Join Type을 결정하는 과정 )


10053 Event의 사용 방법

  alter session set events '10053 trace name context forever, level 1';
      쿼리 실행;
  alter session set events '10053 trace name context off';


  • trace 파일 위치 : User Dump Directory
  • 주의 : 10053 Event는 Query에 대해 Hard Parse( 혹은 Optimization )가 발생할 때만 수행된다는 사실에 유의


최신버전의 trace파일 내용 순서
  1. Query Block생성
  2. Optimizer Parameter, Bug Fix Control(Oracle 10.2.0.2부터출력) 정보
  3. Query Transformation과정
  4. Statistics 정보
  5. Single Table Access방식 선택
  6. Join순서와 Join방식 선택




SCOTT> select /*+ gather_plan_statistics cost_based */
  2       t1.name, v1.name2 , v1.name2
  3   from t_pred1 t1, v_pred v1
  4   where
  5    t1.n = 1 and
  6    t1.id = v1.id2_1(+);

NAME                           NAME2                          NAME2
------------------------------ ------------------------------ ------------------------------
C_COBJ#                        C_COBJ#                        C_COBJ#
                                   생략
I_SYN1                         I_SYN1                         I_SYN1


SCOTT> select * from table(dbms_xplan.display_cursor( null, null, 'all allstats last' ));

PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------------------------------------------------------------------
---- -----------------------------------------------------------------------------------------------------------------------------------
SQL_ID  d2azwbuz9pfk5, child number 0
-------------------------------------
select /*+ gather_plan_statistics cost_based */      t1.name, v1.name2 , v1.name2  from t_pred1 t1, v_pred v1  where   t1.n = 1 and   t1.id =
v1.id2_1(+)

Plan hash value: 3337020919

------------------------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation               | Name        | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem |
------------------------------------------------------------------------------------------------------------------------------------------------------------
|*  1 |  HASH JOIN OUTER        |             |      1 |     20 |   880 |    45   (5)| 00:00:01 |     20 |00:00:00.04 |     172 |   887K|   887K|  934K (0)|
|*  2 |   TABLE ACCESS FULL     | T_PRED1     |      1 |     20 |   280 |     3   (0)| 00:00:01 |     20 |00:00:00.01 |       3 |       |       |          |
|   3 |   VIEW                  | V_PRED      |      1 |  20000 |   585K|    42   (5)| 00:00:01 |  20000 |00:00:00.39 |     169 |       |       |          |
|*  4 |    HASH JOIN            |             |      1 |  20000 |   800K|    42   (5)| 00:00:01 |  20000 |00:00:00.27 |     169 |  1247K|  1247K|  993K (0)|
|   5 |     INDEX FAST FULL SCAN| T_PRED3_IDX |      1 |  20000 |   195K|    14   (0)| 00:00:01 |  20000 |00:00:00.30 |      61 |       |       |          |
|   6 |     TABLE ACCESS FULL   | T_PRED2     |      1 |  20000 |   605K|    26   (0)| 00:00:01 |  20000 |00:00:00.01 |     108 |       |       |          |
------------------------------------------------------------------------------------------------------------------------------------------------------------

Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------

   1 - SEL$1
   2 - SEL$1 / T1@SEL$1
   3 - SEL$2 / V1@SEL$1
   4 - SEL$2
   5 - SEL$2 / T3@SEL$2
   6 - SEL$2 / T2@SEL$2

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - access("T1"."ID"="V1"."ID2_1")
   2 - filter("T1"."N"=1)
   4 - access("T2"."ID"="T3"."ID" AND "T2"."ID2"="T3"."ID2")

Column Projection Information (identified by operation id):
-----------------------------------------------------------

   1 - (#keys=1) "T1"."NAME"[VARCHAR2,30], "V1"."NAME2"[VARCHAR2,30]
   2 - "T1"."ID"[NUMBER,22], "T1"."NAME"[VARCHAR2,30]
   3 - "V1"."ID2_1"[NUMBER,22], "V1"."NAME2"[VARCHAR2,30]
   4 - (#keys=2) "T2"."ID"[NUMBER,22], "T2"."NAME"[VARCHAR2,30]
   5 - "T3"."ID"[NUMBER,22], "T3"."ID2"[NUMBER,22]
   6 - "T2"."ID"[NUMBER,22], "T2"."ID2"[NUMBER,22], "T2"."NAME"[VARCHAR2,30]


45 rows selected.



위의 Predicate정보는 다음과 같이 해석할 수 있다.

  • 2번 단계 filter("T1"."N"=1)에서 Table Full Scan을 통해 조건을 만족하는 Row를 Fetch
  • 4번 단계 ("T2"."ID"="T3"."ID" AND "T2"."ID2"="T3"."ID2")에서 Hash Join을 통해 조건을 만족하는 Row를 Fetch
  • 1번 단계 ("T1"."ID"="V1"."ID2_1")에서 Hash Outer Join을 통해 2번과 4번 단계의 Data들을 Join


  • 위의 실행 계획의 문제점은 Join Predicate Pushing이 발생하지 않았다는 것이다.
  • t1.n=1의 조건을 만족하는 Data에 대해서 Join조건(Join Predicate)을 View v_pred안으로 밀어 넣을 수(Pushing) 있다면 일량을 줄일 수 있는 기회가 있다.
  • Join Predicate Pushing : Query Transformatino기법으로 인해 t2.id = t1.id라는 기존에 존재하지 않던 Join조건이 추가 - page. 76참고


위와 같은 상황에서 우리는 10053Event를 이용해서 왜 Query Transformation중에 Join Predicate Pushing이 발생하지 않았는지를 추적하는 것이다.


***************************************
GENERAL PLANS
***************************************
Considering cardinality-based initial join order.
***********************
Join order[1]:  T_PRED1[T1]#1  V_PRED[V1]#0
***************
Now joining: V_PRED[V1]#0
***************
NL Join
  Outer table: Card: 20.00  Cost: 3.00  Resp: 3.00  Degree: 1  Bytes: 14
  Inner table: V_PRED  Alias: V1
  Access Path: TableScan
    NL Join:  Cost: 83.05  Resp: 83.05  Degree: 0
      Cost_io: 83.00  Cost_cpu: 649401
      Resp_io: 83.00  Resp_cpu: 649401
  Best NL cost: 83.05
          resc: 83.05 resc_io: 83.00 resc_cpu: 649401
          resp: 83.05 resp_io: 83.00 resp_cpu: 649401
Outer Join Card:  20.00 = max ( outer (20.00), (outer (20.00) * inner (20000.00) * sel (5.0000e-05) )
Join cardinality for HJ/SMJ (no post filters):  400000.00, outer: 20.00, inner: 20000.00, sel: 1 
Join Card - Rounded: 20 Computed: 20.00
Best:: JoinMethod: NestedLoop
       Cost: 83.05  Degree: 1  Resp: 83.05  Card: 20.00  Bytes: 52
***********************
Best so far: Table#: 1  cost: 3.0042  card: 20.0000  bytes: 280
             Table#: 0  cost: 83.0542  card: 20.0000  bytes: 1040
(newjo-stop-1) k:0, spcnt:0, perm:1, maxperm:2000
*********************************
Number of join permutations tried: 1
*********************************
Final - All Rows Plan:  Best join order: 1
  Cost: 83.0542  Degree: 1  Card: 20.0000  Bytes: 1040
  Resc: 83.0542  Resc_io: 83.0000  Resc_cpu: 649401
  Resp: 83.0542  Resp_io: 83.0000  Resc_cpu: 649401
kkoipt: Query block SEL$1 (#1)
******* UNPARSED QUERY IS *******
SELECT /*+ */ "T1"."NAME" "NAME","V1"."NAME2" "NAME2","V1"."NAME2" "NAME2" 
FROM "SCOTT"."T_PRED1" "T1",(SELECT /*+*/ "T2"."ID" "ID2_1","T2"."NAME" "NAME2" FROM "SCOTT"."T_PRED2" "T2","SCOTT"."T_PRED3" "T3" 
WHERE "T2"."ID"="T3"."ID" AND "T2"."ID2"="T3"."ID2"AND "T2"."ID"="T1"."ID"AND "T3"."ID"="T1"."ID") "V1" WHERE "T1"."N"=1
kkoqbc-end
          : call(in-use=132596, alloc=147368), compile(in-use=146608, alloc=148236)
CBQT: Saved costed qb# 2 (SEL$639F1A6F)
JPPD: New cost worse than best so far, Cost = 83.05
JPPD: Will not use JPPD from query block SEL$1 (#1).
JPPD: Applying transformation directives
JPPD: Checking validity of push-down in query block SEL$2 (#2)
JPPD:   No view found to push predicate into.
JPPD: Checking validity of push-down in query block SEL$1 (#1)
JPPD:   Pushdown from SEL$1 (#1) passed validity checks.
JPPD: Performing join predicate push-down (no transformation phase)
          From SEL$1 (#1) to SEL$2 (#2)
FPD: Considering simple filter push in SEL$1 (#1)
FPD:   Current where clause predicates in SEL$1 (#1) :
         "T1"."N"=1 AND "T1"."ID"="V1"."ID2_1"(+)
kkogcp: try to generate transitive predicate from check constraints for SEL$1 (#1)
predicates with check contraints: "T1"."N"=1 AND "T1"."ID"="V1"."ID2_1"(+)
after transitive predicate generation: "T1"."N"=1 AND "T1"."ID"="V1"."ID2_1"(+)
finally: "T1"."N"=1 AND "T1"."ID"="V1"."ID2_1"(+)
FPD: Considering simple filter push in SEL$2 (#2)
FPD:   Current where clause predicates in SEL$2 (#2) :
         "T2"."ID"="T3"."ID" AND "T2"."ID2"="T3"."ID2"
kkogcp: try to generate transitive predicate from check constraints for SEL$2 (#2)
predicates with check contraints: "T2"."ID"="T3"."ID" AND "T2"."ID2"="T3"."ID2"
after transitive predicate generation: "T2"."ID"="T3"."ID" AND "T2"."ID2"="T3"."ID2"
finally: "T2"."ID"="T3"."ID" AND "T2"."ID2"="T3"."ID2"
kkoqbc-start
            : call(in-use=132604, alloc=147368), compile(in-use=100312, alloc=148236)



Cost가 더 높기 때문에 JPPD를 수행 하지 않을것임을 의미한다.

SELECT /*+ */ "T1"."NAME" "NAME","V1"."NAME2" "NAME2","V1"."NAME2" "NAME2" 
FROM "SCOTT"."T_PRED1" "T1",(SELECT /*+*/ "T2"."ID" "ID2_1","T2"."NAME" "NAME2" FROM "SCOTT"."T_PRED2" "T2","SCOTT"."T_PRED3" "T3" 
WHERE "T2"."ID"="T3"."ID" AND "T2"."ID2"="T3"."ID2"AND "T2"."ID"="T1"."ID"AND "T3"."ID"="T1"."ID") "V1" WHERE "T1"."N"=1
kkoqbc-end
          : call(in-use=132596, alloc=147368), compile(in-use=146608, alloc=148236)
CBQT: Saved costed qb# 2 (SEL$639F1A6F)
JPPD: New cost worse than best so far, Cost = 83.05
JPPD: Will not use JPPD from query block SEL$1 (#1).


"T2"."ID"="T1"."ID"AND "T3"."ID"="T1"."ID" 부분과 JPPD: Will not use JPPD from query block SEL$1 (#1)부분에 주목하자.
  • =>Cost가 더 높기 때문에 JPPD를 수행 하지 않을것임을 의미한다.


이런 류의 정보는 10053 Event가 아니면 얻을 수 없는 것이다.
"데이터베이스 스터디모임" 에서 2009년에 "OPTIMIZING ORACLE OPTIMIZER " 도서를 스터디하면서 정리한 내용 입니다.

- 강좌 URL : http://www.gurubee.net/lecture/3907

- 구루비 강좌는 개인의 학습용으로만 사용 할 수 있으며, 다른 웹 페이지에 게재할 경우에는 출처를 꼭 밝혀 주시면 고맙겠습니다.~^^

- 구루비 강좌는 서비스 제공을 위한 목적이나, 학원 홍보, 수익을 얻기 위한 용도로 사용 할 수 없습니다.

댓글등록
SQL문을 포맷에 맞게(깔끔하게) 등록하려면 code() 버튼을 클릭하여 작성 하시면 됩니다.
로그인 사용자만 댓글을 작성 할 수 있습니다. 로그인, 회원가입