V$SQL SHARED CURSOR
EXEM Knowledge Base
목차 |
[편집] 기본 정보
[편집] 개요
각 Child Cursor별로 Cursor 공유가 이루어지지 않은 이유를 제공하는 뷰이다. 가령 Bind Mismatch가 생긴 경우에는 BIND_MISMATCH 컬럼의 값이 Y로 기록된다.
[편집] 지원
8i 이상
[편집] 컬럼
| 이름 | 유형 | 설명 |
| ADDRESS | RAW(4) | Address of the child cursor |
| KGLHDPAR | RAW(4) | Address of the parent cursor |
| UNBOUND_CURSOR | VARCHAR2(1) | N) The existing child cursor was not fully built (in other words, it was not optimized) |
| SQL_TYPE_MISMATCH | VARCHAR2(1) | N) The SQL type does not match the existing child cursor |
| OPTIMIZER_MISMATCH | VARCHAR2(1) | N) The optimizer environment does not match the existing child cursor |
| OUTLINE_MISMATCH | VARCHAR2(1) | N) The outlines do not match the existing child cursor |
| STATS_ROW_MISMATCH | VARCHAR2(1) | N) The existing statistics do not match the existing child cursor |
| LITERAL_MISMATCH | VARCHAR2(1) | N) Non-data literal values do not match the existing child cursor |
| SEC_DEPTH_MISMATCH | VARCHAR2(1) | N) Security level does not match the existing child cursor |
| EXPLAIN_PLAN_CURSOR | VARCHAR2(1) | N) The child cursor is an explain plan cursor and should not be shared |
| BUFFERED_DML_MISMATCH | VARCHAR2(1) | N) Buffered DML does not match the existing child cursor |
| PDML_ENV_MISMATCH | VARCHAR2(1) | N) PDML environment does not match the existing child cursor |
| INST_DRTLD_MISMATCH | VARCHAR2(1) | N) Insert direct load does not match the existing child cursor |
| SLAVE_QC_MISMATCH | VARCHAR2(1) | N) The existing child cursor is a slave cursor and the new one was issued by the coordinator (or, the existing child cursor was issued by the coordinator and the new one is a slave cursor) |
| TYPECHECK_MISMATCH | VARCHAR2(1) | N) The existing child cursor is not fully optimized |
| AUTH_CHECK_MISMATCH | VARCHAR2(1) | N) Authorization/translation check failed for the existing child cursor |
| BIND_MISMATCH | VARCHAR2(1) | N) The bind metadata does not match the existing child cursor |
| DESCRIBE_MISMATCH | VARCHAR2(1) | N) The typecheck heap is not present during the describe for the child cursor |
| LANGUAGE_MISMATCH | VARCHAR2(1) | N) The language handle does not match the existing child cursor |
| TRANSLATION_MISMATCH | VARCHAR2(1) | N) The base objects of the existing child cursor do not match |
| ROW_LEVEL_SEC_MISMATCH | VARCHAR2(1) | N) The row level security policies do not match |
| INSUFF_PRIVS | VARCHAR2(1) | N) Insufficient privileges on objects referenced by the existing child cursor |
| INSUFF_PRIVS_REM | VARCHAR2(1) | N) Insufficient privileges on remote objects referenced by the existing child cursor |
| REMOTE_TRANS_MISMATCH | VARCHAR2(1) | N) The remote base objects of the existing child cursor do not match |
| LOGMINER_SESSION_MISMATCH | VARCHAR2(1) | N) |
| INCOMP_LTRL_MISMATCH | VARCHAR2(1) | N) |
[편집] 참고 사항
[편집] High Version Count
SQL Text는 동일하지만 공유되지 못하는 Child Cursor의 개수는 V$SQL_AREA.VERSION_COUNT 컬럼의 값으로 알 수 있다. 이 컬럼 값이 높은 경우를 흔히 Version Count가 높다고 표현한다. 높은 Version Count는 다음과 같은 문제와 관련이 있다.
- 불필요한 Hard Parse
- Library Cache 공간의 낭비
- 불안정한 실행 계획
Version Count가 지나치게 높은 경우에는 V$SQL_SHARED_CURSOR 뷰를 이용해서 Cursor가 공유되지 못하는 이유를 파악한 후 문제를 해결해야 한다.
[편집] Cursor가 공유되지 못하는 일반적인 이유들
- Optimizer Mode의 변경(ALL_ROWS/FIRST_ROWS/CHOOSE). OPTIMIZER_MODE_MISMATCH 컬럼값으로 확인
- Optimizer Parameter의 변경(예: OPTIMIZER_INDEX_CACHING 파라미터). OPTIMIZER_MISMATCH 컬럼값으로 확인
- Trace Event 활성화(예: 10046 Event, DBMS_MONITOR, SQL_TRACE). STATS_ROW_MISMATCH 컬럼값으로 확인
- Translation 발생(예: Schema A와 Schema B가 동일한 이름의 테이블을 사용). AUTH_CHECK_MISMATCH, TRANSLATION_MISMATCH 컬럼값으로 확인
- Bind Mismatch 발생(예: 길이가 다른 문자열 사용). BIND_MISMATCH 컬럼값으로 확인
[편집] 예제
[편집] Bind Mismatch에 의한 Version Count 증가
동일한 Bind 변수에 대해 서로 길이가 다른 값을 사용하면 Bind Mismatch가 발생할 수 있다. 아래의 예를 보자.
-- 동일한 Text의 SQL을 Bind 변수의 길이를 변경하며 수행 var x varchar2(1); exec :x := 't'; select /* bind_test */ * from bind_test where name = :x; var x varchar2(150); exec :x := 't'; select /* bind_test */ * from bind_test where name = :x; var x varchar2(300); exec :x := 't'; select /* bind_test */ * from bind_test where name = :x;
-- Version Count가 3으로 모두 공유되지 못했음을 확인할 수 있다. SELECT version_count, sql_text FROM v$sqlarea WHERE sql_text like 'select /* bind_test */%'; version_count sql_text ---------------- -------------------------------------------------------------------- 3 select /* bind_test */ * from bind_test where name = :x
오라클은 Varchar 타입의 Bind 변수의 경우 그 길이를 다음과 같은 구간의 값으로 올림한다.
- 32
- 128
- 2000
- 4000
같은 구간 사이에 속하는 길이는 Bind 변수는 동일한 길이로 취급되지만, 구간이 다른 경우에는 Bind Mismatch가 발생한다. V$SQL_BIND_METADATA 뷰를 이용하면 이것을 확인할 수 있다.
select address, max_length, bind_name from v$sql_bind_metadata
where child_address in (
SELECT child_address FROM v$sql WHERE sql_text like 'SELECT /* bind_test */%'
);
address max_length bind_name
----------------------- --------------- -------------
0000000084884B10 32 X
0000000084973280 128 X
0000000084973E70 2000 X
위와 같은 현상을 없애려면 동일한 크기의 Bind 변수를 선언해야 한다.
Java 언어에서는 PreparedStatement를 통해 Bind 변수를 사용한다. 이 경우에도 동일한 문제가 발생한다. 즉, 아래의 두 PreparedStatement는 실제로는 공유가 되지 못한다.
PreparedStatement stmt = null;
String s1 = "a";
stmt = con.prepareStatement("SELECT /* bind_test */ * FROM bind_test WHERE name = ?");
stmt.setString(1, s1);
ResultSet rs = stmt.executeQuery();
stmt.close();
String s2 = "a";
for(int idx=0; idx<50; idx++) s2 = s2+" ";
stmt = con.prepareStatement("SELECT /* bind_test */ * FROM bind_test WHERE name = ?");
stmt.setString(1, s2);
rs = stmt.executeQuery();
stmt.close();
이러한 현상은 대부분의 경우 큰 문제가 되지 않는다. 하지만 하나의 SQL 문장이 많은 수의 Bind 변수를 사용하고, 각 Bind 변수마다 Bind Mismatch개 발생할 경우 그 경우의 수는 기하급수적으로 늘어날 수 있다. 이런 경우에는 다음과 같은 방법을 사용할 수 있다.
String x = "x";
// V$SQL_BIND_METADATA 뷰를 통해 확인한 최대값만큼 Dummy Blank를 붙인다.
for(int i=0; i<xxxx; i++) x+= " ";
...
// RTRIM Function을 사용해서 Dummy Blank가 인식되지 않도록 한다.
stmt = con.prepareStatement("select /* bind_test */ * from bind_test where name = RTRIM(?)");
..
위와 같이 코드를 수정하면 항상 같은 크기의 문자열이 전송되므로, Bind Mismatch가 발생하지 않는다.
[편집] 관련 정보