DATOR


옵티마이져 - 힌트 : 파싱과 구문오류 SQL Fundamental


힌트의 파싱과 힌트구문 오류에 대한 처리
=======================================

옵티마이져가 쿼리를 분석하여 실행계획을 수립할때 힌트도 파싱을 합니다..

일반적으로 힌트에서 힌트간의 우선 순위는 거의 없습니다..
일부 힌트의 경우 특정힌트가 나오면 무시되거나 하는것은 있습니다..

우리가 쿼리 문장에 힌트를 기술시 힌트에 따라, 또는 테이블 엘리어스를 사용하는것에 따라
또는 테이블명을 직접 기술해야만 하는 힌트도 있습니다..

 

힌트의 파싱

옵티마이져가 힌트를 파싱할때 쿼리 블럭의 스키마도 같이 파싱하는 것은
  아닙니다.. 단지 구문을 파싱하며 체크할 뿐입니다..

즉 간단히 예를 들면
SELECT  *
  FROM EMP
 WHERE EMPNO > 10 ;

이 구문을 가지고 예를 들면 다음과 같습니다..

- /*+ FULL          */  => 힌트 무시
- /*+ FULL(EMP)     */  => 힌트 인식 - 정상 FULL SCAN 처리
- /*+ FULL(A)       */  => 힌트 인식 - INDEX SCAN
- /*+ FULL(A B)     */  => 힌트 무시
- /*+ AAA FULL(EMP) */  => 힌트 인식 - 정상 FULL SCAN 처리
                           힌트의 구문이 아닌 경우는 주석으로 인식하여 무시한다.

 

힌트의 구문오류

힌트에 관한 관련 문서들을 보면
hint를 무시하는 경우
- hint가 쓰인 comment가 DELETE, SELECT, UPDATE 키워드 뒤에 오지 않고,
   다른 곳에 쓰여 있는 경우
- hint가 Syntax error를 가진 경우
  (동일한 comment내에 error를 가지지 않고 올바로 표현된 다른 hint들은 인정)
- 충돌한 hint의 조합들은 무시(한 comment내에 두 개 이상의 hint가 있을 경우,
     Optimizer가 어떤 hint를 먼저 써야하는지 모르는 경우)
     (동일한 comment내에 충돌한 hint외에 다른 hint는 인정.)
라고 되어 있는데 단순히 위와 같지만은 않은 부분이 있어 사용상의 주의가 필요한 부분이 있습니다.

우리가 알다시피 힌트의 적용에서 엘리어스나 인덱스, 테이블 명칭을 잘못 기술하면
 그 힌트는 무시되게 됩니다.

하지만 우리가 잘 모르는 것 한가지는 여러 힌트의 기술시에 선행 기술한 힌트에서 구문을 잘못
  작성하게 되면 이후에 기술한 다른 힌트도 전부 무시 되는 경우도 발생하게 됩니다.
(하나의 힌트에서 철자등이 틀린경우 이후에 기술된 힌트가 다 무시 되는 경우도
  있으므로 주의하셔야 합니다..)

간단한 예)
SELECT
       NO, NO2
  FROM COPY_T
 WHERE NO IN ( :A, :B )

이와 같은 쿼리가 있습니다.
지정한 힌트는 /*+ ORDERED INDEX(COPY_T COPY_T_PK) FIRST_ROWS USE_CONCAT */ 형식으로 옵티마이져 모드와 인덱스 사용 지정 등의 동작여부로 테스트 했습니다.
힌트의 종류가 옵티마이져의 버젼에 따라 미세하게 다른 부분이 있어 모든 버젼에서 동일하지는 않지만 대부분 플랜으로 확인했습니다.

여기에 힌트를 지정시 FIRST_ROWS를 사용한것은 항상 CBO로 동작하게 하려고 한것입니다.
단순히 힌트를 잘못 지정시 모두 이후 지정된 힌트가 모두 무시되는것은 아니며
힌트의 종류(특성)에 따라서 처리가 달라짐을 알 수 있습니다.


================================================================================

Optimization Approaches and Goals
  => 자신의 힌트만 무시
ALL_ROWS
FIRST_ROWS(n)
CHOOSE
RULE

Access Paths
  => 자신의 힌트뿐 아니라 이후에 기술된 모든 힌트도 같이 무시
FULL
ROWID
CLUSTER
HASH
INDEX
INDEX_ASC
INDEX_COMBINE
INDEX_JOIN
INDEX_DESC
INDEX_FFS
NO_INDEX
AND_EQUAL

Query Transformations
=> 자신의 힌트만 무시
USE_CONCAT
NO_EXPAND
REWRITE
NOREWRITE
MERGE
NO_MERGE
STAR_TRANSFORMATION
FACT
NO_FACT

Join Orders
  => 자신의 힌트만 무시
ORDERED
STAR

Join Operations
  => 자신의 힌트뿐 아니라 이후에 기술된 모든 힌트도 같이 무시
USE_NL
USE_MERGE
USE_HASH
DRIVING_SITE
LEADING
HASH_AJ, MERGE_AJ, and NL_AJ
HASH_SJ, MERGE_SJ, and NL_SJ

Parallel Execution
  => 자신의 힌트뿐 아니라 이후에 기술된 모든 힌트도 같이 무시
PARALLEL
NOPARALLEL
PQ_DISTRIBUTE
PARALLEL_INDEX
NOPARALLEL_INDEX

Additional Hints
  => 자신의 힌트뿐 아니라 이후에 기술된 모든 힌트도 같이 무시
APPEND
NOAPPEND
CACHE
NOCACHE
UNNEST
NO_UNNEST
PUSH_PRED
NO_PUSH_PRED
PUSH_SUBQ
ORDERED_PREDICATES
CURSOR_SHARING_EXACT
=============================================================================

LEADING 처럼 집합을 기술해야 하는 힌트중에는 집합을 기술하지 않으면 철자오류와
  같은 처리가 발생하게 됩니다.
NOPARALLEL(X 4)처럼 힌트에서 잘못 지정하여 문법을 어기게 되어도 역시 철자오류와
  같은 처리가 발생하게 됩니다.

힌트의 종류 및 구문의 특성에 따라 집합의 지정 오류등에 따라 처리가 힌트마다
  조금씩 달라질 수 있다.

즉 힌트의 구문을 보고 옵티마이져가 잘못 기술된 힌트가 무엇인지를 인식할수 있느냐
  없느냐에 따라서 달라집니다.
예를 들어 /*+ NOPARALLEL(X) FIRST_ROWS */ 과 같은 힌트가 있습니다.
이는 정상적인 힌트이며 아래와 같이 잘못 기술시 옵티마이져가 파싱하여 인식하는것이
  달라지게 됩니다.
  /*+ NO PARALLEL(X) FIRST_ROWS */  => 정상   힌트구문으로 인식
  /*+ NOP ARALLEL(X) FIRST_ROWS */  => 잘못된 힌트구문으로 인식

하지만 오류로 인식된 힌트의 경우 힌트의 구분에 따라 처리는 일정하게 된다.

실제 쿼리 작성시 힌트의 지정 및 튜닝시 힌트의 제거를 위해서 간단히 힌트의
 구문을 변경시키거나 잘못 지정한 경우 원하지 않는 실행계획으로 처리될수
 있으므로 주의를 기울여야 합니다.

도움이 되셨기를...
그럼 이만!


보너스로 문제 하나.


여러분이 옵티마이져 입장이라고 생각해 보세요...

위의 쿼리에서 힌트를 다음과 같이 지정할때 어떤 실행계획이 나올까요...?
SELECT /*+ FIRST_ROWS INDEX(COPY_T COPY_T_PK) USE_CONCAT NO_EXPAND  */
       NO, NO2
  FROM COPY_T
 WHERE NO IN ( :A, :B )

실제 수행 트레이스를 보면 다음과 같습니다.

Rows     Row Source Operation
-------  ---------------------------------------------------
      2  TABLE ACCESS BY INDEX ROWID COPY_T
     32   INDEX FULL SCAN (object id 26627)

Rows     Execution Plan
-------  ---------------------------------------------------
      0  SELECT STATEMENT   GOAL: HINT: FIRST_ROWS
      2   TABLE ACCESS (BY INDEX ROWID) OF 'COPY_T'
     32    INDEX (FULL SCAN) OF 'COPY_T_PK' (UNIQUE)

정리해서 생각해보시면 재밌는 옵티마이져의 세계를 엿보실수 있을겁니다...

Leave Comments