2013년 7월 5일 금요일

oracle cursor sharing 문제

/*
오라클의 cursor_sharing = FORCE 의 폐혜

테스트 환경 : Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - 64bit
요점 : cursor_sharing = FORCE 환경에서 SQL문에 주어진 상수 마저 변수화 되므로 잘못된 실행 계획을 표현함
*/

-- 테스트를 위해서 아래와 같은 테이블 및 인덱스를 생성한다.
CREATE TABLE DNJSQO_T
(
  C1 VARCHAR2(100) NOT NULL,
  C2 NUMBER(10) NOT NULL
);

INSERT INTO DNJSQO_T
SELECT LPAD(LEVEL, 10, '0'), LEVEL
FROM   DUAL
CONNECT BY LEVEL <= 10000;

COMMIT;

CREATE INDEX DNJSQO_T_IDX ON DNJSQO_T (C1);

--테스트를 위해서 SESSION LEVEL에서 cursor_sharing = FORCE 로 설정한다.
ALTER SESSION SET CURSOR_SHARING = FORCE;

--TRACE를 수행한다.
ALTER SESSION SET SQL_TRACE = TRUE;

--생성한 테이블에 아래와 같은 SQL을 각각 실행한다.
SELECT /* %% TEST */ *
FROM   DNJSQO_T
WHERE  C1 LIKE '%' || :1 || '%';

SELECT /* % TEST */ *
FROM   DNJSQO_T
WHERE  C1 LIKE :1 || '%';

/*
여기서 부터는 TRACE 결과임
두가지 SQL 모두 실행계획은 INDEX RANGE SCAN 이지만 읽은 블럭수를 확인해보면 전혀 다르다.
양쪽 '%' 로 조회한 SQL은 INDEX 32블럭(아마도 INDEX FULL SCAN) 을 읽어서 한 건을 찾고 테이블 엑세스를 하였으나,
우측 '%' 로 조회한 SQL은 INDEX 2블럭을 읽어서 한 건을 찾고 테이블을 엑세스 하였다.
이러한 현상이 발생하는 이유는 cursor_sharing 기능으로 SQL에 포함된 상수마저 변수 처리를 함으로써 해당 변수에 어떤 값이 대입될지 알 수 없으므로
발생하는 문제로 생각됨
*/

SELECT /* %% TEST */ *
FROM   DNJSQO_T
WHERE  C1 LIKE :"SYS_B_0" || :1 || :"SYS_B_1"

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        1      0.02       0.02          0         33          0           1
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        3      0.02       0.02          0         33          0           1

Misses in library cache during parse: 1
Optimizer mode: FIRST_ROWS
Parsing user id: 36

Rows     Row Source Operation
-------  ---------------------------------------------------
      1  TABLE ACCESS BY INDEX ROWID DNJSQO_T (cr=33 pr=0 pw=0 time=20430 us)
      1   INDEX RANGE SCAN DNJSQO_T_IDX (cr=32 pr=0 pw=0 time=20407 us)(object id 60949)


Elapsed times include waiting on following events:
  Event waited on                             Times   Max. Wait  Total Waited
  ----------------------------------------   Waited  ----------  ------------
  SQL*Net message to client                       1        0.00          0.00
  SQL*Net message from client                     1        0.00          0.00
********************************************************************************

SELECT /* % TEST */ *
FROM   DNJSQO_T
WHERE  C1 LIKE :1 || :"SYS_B_0"

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        1      0.00       0.00          0          3          0           1
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        3      0.00       0.00          0          3          0           1

Misses in library cache during parse: 1
Optimizer mode: FIRST_ROWS
Parsing user id: 36

Rows     Row Source Operation
-------  ---------------------------------------------------
      1  TABLE ACCESS BY INDEX ROWID DNJSQO_T (cr=3 pr=0 pw=0 time=78 us)
      1   INDEX RANGE SCAN DNJSQO_T_IDX (cr=2 pr=0 pw=0 time=50 us)(object id 60949)

댓글 없음:

댓글 쓰기