실행계획 |
---|
{code:sql} |
Execution Plan
h3. 옵티마이저의 최적화 수행단계를 요약 ( Page.246 )
* 1. 사용자가 던전 쿼리수행을 위해 후보군이 될만한 실행계획들을 찾아낸다.
* 2. 데이터 딕셔너리에 미리 수집해 놓은( 다아니믹 셈플링은 논외로 함 ) 오브젝트 통계 및 시스템 통계정보를 이용해 각 실행계획의 예상비용을 산정한다.
* 3. 각 실행계획의 비용을 비교해서 최소비용을 갖는 하나를 선택한다.
!4_4.PNG!
h3. 02 SQL 처리 과정 ( 그림 4-5, Page 247 )
* 소프트 파싱 : 파싱 단계에서 SQL 커서를 메모리에서 찾아서 곧바로 실행 단계로..
* 하드 파싱 : 찾는데 실패해 최적화 및 Row-Source 생성 단계를 거치는 것
h3. (1) SQL 파싱
* 1. SQL 문장을 이루는 개별 구성요소를 분석하고 파싱해서 파싱 트리를 만든다. ( Syntax 체크 )
* 2. Semanatic 체크를 통해 의미상 오류가 없는지 체크. ( 권한, 컬럼 )
* 3. 해싱 알고리즘을 이용해 해당 SQL 커서가 Shared Pool에 캐싱돼 있는지를 확인한다.
** SQL ASCII 텍스트에 대한 숫자 값을 계산 하고, 해쉬 값으로 변환
* 4. 파싱을 요청한 사용자가 다르거나 옵티마이저 관련 파라미터 설정이 다르다면 새로운 SQL 커서를 생성해야 한다.
** SCOTT.EMP OR HR.EMP
h3. (2) SQL 최적화
* Query Transformer : 최적화하기 쉬운 행태로 변환을 시도 ( 결과 동일 보장 )
* Plan Generator : 하나의 쿼리를 수행하는 데 있어, 후보군이 될만한 실행계획들을 생성해 내는 역할을 한다.
* Estimator : 쿼리 오퍼레이션 각 단계의 선택도, 카디널리티, 비용를 계산하고, 궁극적으로는
실행계획 전체에 대한 총 비용을 계산해 낸다. 이는 어디까지나 예상치
각 단계를 수행하는데 필요한 I/O, CPU, 메모리 사용량 등을 예측하기 위해 데이터 베이스 오브젝트 통계정보와
하드웨어적인 시스템 성능 통계 정보를 이용한다.
h3. Adaptive search strategy
* 쿼리 수행 시 예상되는 총 수행시간에 비해 쿼리 최적화에 걸리는 시간이 일정비율을 넘지 않도록 적응적 탐색 전략
h3. Multiple Initial orderings heuristic
* 조인 순서를 무순위로 평가하는게 아니라 최적의 실행계획을 발결한 가능이 높은 순서대로 비용을 평가하는 것을 말한다.
h3. (3) Row-Source Generation
* 실행 가능한 코드 또는 프로시저 형태로 포맷팅
{code:sql}
-- 실행계획 : 개념적
Execution Plan
---------------------------------------------------------
0 SELECT STATEMENT Optimizer=ALL_ROWS
1 0 NESTED LOOPS
2 1 TABLE ACCESS (BY INDEX ROWID) OF 'DEPT'
3 2 INDEX (RANGE SCAN) OF 'DEPT_X01' (NON-UNIQUE)
4 1 TABLE ACCESS (BY INDEX ROWID) OF 'EMP'
5 4 INDEX (RANGE SCAN) OF 'EMP_X01' (NON_UNIQUE)
-- Row-Source
<<outer_loop>>
LOOP
outer_rid := index_range_scan('DEPT_X01', search_key);
outer_rec := table_access_by_index_rowid('DEPT', outer_rid);
EXIT outer_loop WHEN outer_rec IS NULL;
<<iner_loop>>
LOOP
inner_rid := index_range_scan('EMP_X01', outer_rec.deptno);
iner_rec := table_acces_by_index_rowid('EMP', inner_rid);
EXIT inner_loop WHEN inner_rec, inner_rec);
selected_rows := selected_rows + 1;
END LOOP inner_loop;
END LOOP outer_loop;
DBMS_OUTPUT.PUT_LINE(selected_rows || ' rows selected.');
라이브러리 캐시 오브젝트 |
---|
{code:sql} SYSTEM @ > SELECT NAMESPACE,GETS,PINS, RELOADS, INVALIDATIONS FROM V$LIBRARYCACHE; |
NAMESPACE GETS PINS RELOADS INVALIDATIONS
27 개의 행이 선택되었습니다.
h3. Shared Pool
* LRU 알고리즘
* 9i 이전부터는 1의 shared pool latch 관리, 9i부터 Sub Pool로 래치도 7개까지
* 순간적으로 과도한 하드 파싱 부하를 일으킨다면 shared pool 래치에 대한 경합 현상이 나타날 수 있다.
{code:sql}
SYSTEM @ > SELECT CHILD#, GETS, MISSES, SLEEPS, IMMEDIATE_GETS, IMMEDIATE_MISSES
2 FROM V$LATCH_CHILDREN
3 WHERE NAME = 'shared pool'
4 order by 1;
CHILD# GETS MISSES SLEEPS IMMEDIATE_GETS IMMEDIATE_MISSES
---------- ---------- ---------- ---------- -------------- ----------------
1 252831947 434433 27617 91532 154
2 244664337 435765 29035 90496 170
3 252170145 437037 28759 86524 170
4 351294992 424751 27971 69115 127
5 257473630 443297 29409 85666 139
6 52 0 0 0 0
7 52 0 0 0 0
7 개의 행이 선택되었습니다.
커서 공유 테스트 |
---|
{code:sql} |
SYSTEM @ > SELECT * FROM V$VERSION;
BANNER
SYSTEM @ > CREATE TABLE SYSTEM.JHLEE68_LCO_TEST_20160408 AS
2 SELECT LEVEL NO, CHR( LEVEL ) NAME
3 FROM DUAL
4 CONNECT BY LEVEL <= 100;
테이블이 생성되었습니다.
SYSTEM @ XXXXX> SELECT SQL_ID, PARSE_CALLS, LOADS, EXECUTIONS, INVALIDATIONS
2 , DECODE( SIGN(INVALIDATIONS), 1, (LOADS-INVALIDATIONS), 0 ) RELOADS
3 FROM V$SQL
4 WHERE SQL_TEXT LIKE '%CURSOR_TEST3%'
5 AND SQL_TEXT NOT LIKE '%V$SQL%';
선택된 레코드가 없습니다.
SYSTEM @ XXXXX> SELECT /* CURSOR_TEST3 */ * FROM JHLEE68_LCO_TEST_20160408 WHERE NO = 1;
NO NAME ETC ETC2
SYSTEM @ XXXXX> SELECT SQL_ID, PARSE_CALLS, LOADS, EXECUTIONS, INVALIDATIONS
2 , DECODE( SIGN(INVALIDATIONS), 1, (LOADS-INVALIDATIONS), 0 ) RELOADS
3 FROM V$SQL
4 WHERE SQL_TEXT LIKE '%CURSOR_TEST3%'
5 AND SQL_TEXT NOT LIKE '%V$SQL%';
SQL_ID PARSE_CALLS LOADS EXECUTIONS INVALIDATIONS RELOADS
SYSTEM @ XXXXX> save LCO_CH3
file LCO_CH3.sql(이)가 생성되었습니다
SYSTEM @ XXXXX> SELECT /* CURSOR_TEST3 */ * FROM JHLEE68_LCO_TEST_20160408 WHERE NO = 1;
NO NAME ETC ETC2
SYSTEM @ XXXXX> @LCO_CH3
SQL_ID PARSE_CALLS LOADS EXECUTIONS INVALIDATIONS RELOADS
SYSTEM @ XXXXX> SELECT /* CURSOR_TEST3 */ * FROM JHLEE68_LCO_TEST_20160408 WHERE NO = 1;
NO NAME ETC ETC2
SYSTEM @ XXXXX> @LCO_CH3
SQL_ID PARSE_CALLS LOADS EXECUTIONS INVALIDATIONS RELOADS
SYSTEM @ XXXXX> COL SQL_TEXT FOR A100
SYSTEM @ XXXXX> SELECT SQL_TEXT, INVALIDATIONS
2 FROM V$SQLAREA
3 WHERE SQL_ID = '95smyj0461xrw';
SQL_TEXT INVALIDATIONS
SYSTEM @ XXXXX> BEGIN
2 DBMS_STATS.GATHER_TABLE_STATS(
3 OWNNAME => 'SYSTEM'
4 , TABNAME => 'JHLEE68_LCO_TEST_20160408'
5 , CASCADE => TRUE
6 , ESTIMATE_PERCENT =>'1'
7 , DEGREE => '1'
8 , METHOD_OPT=>'FOR ALL COLUMNS SIZE 1'
9 , NO_INVALIDATE=>DBMS_STATS.AUTO_INVALIDATE ); -- DBMS_STATS.AUTO_INVALIDATE
10 END;
11 /
PL/SQL 처리가 정상적으로 완료되었습니다.
SYSTEM @ XXXXX> @LCO_CH3
SQL_ID PARSE_CALLS LOADS EXECUTIONS INVALIDATIONS RELOADS
SYSTEM @ XXXXX> COL SQL_TEXT FOR A100
SYSTEM @ XXXXX> SELECT SQL_TEXT, INVALIDATIONS
2 FROM V$SQLAREA
3 WHERE SQL_ID = '95smyj0461xrw';
SQL_TEXT INVALIDATIONS
SYSTEM @ XXXXX> BEGIN
2 DBMS_STATS.GATHER_TABLE_STATS(
3 OWNNAME => 'SYSTEM'
4 , TABNAME => 'JHLEE68_LCO_TEST_20160408'
5 , CASCADE => TRUE
6 , ESTIMATE_PERCENT =>'1'
7 , DEGREE => '1'
8 , METHOD_OPT=>'FOR ALL COLUMNS SIZE 1'
9 , NO_INVALIDATE=> FALSE ); --
10 END;
11 /
PL/SQL 처리가 정상적으로 완료되었습니다.
SYSTEM @ XXXXX> @LCO_CH3
SQL_ID PARSE_CALLS LOADS EXECUTIONS INVALIDATIONS RELOADS
SYSTEM @ XXXXX>
SYSTEM @ XXXXX> COL SQL_TEXT FOR A100
SYSTEM @ XXXXX> SELECT SQL_TEXT, INVALIDATIONS
2 FROM V$SQLAREA
3 WHERE SQL_ID = '95smyj0461xrw';
SQL_TEXT INVALIDATIONS
SYSTEM @ XXXXX> SELECT /* CURSOR_TEST3 */ * FROM JHLEE68_LCO_TEST_20160408 WHERE NO = 1;
NO NAME ETC ETC2
SYSTEM @ XXXXX> @LCO_CH3
SQL_ID PARSE_CALLS LOADS EXECUTIONS INVALIDATIONS RELOADS
SYSTEM @ XXXXX>
SYSTEM @ XXXXX> COL SQL_TEXT FOR A100
SYSTEM @ XXXXX> SELECT SQL_TEXT, INVALIDATIONS
2 FROM V$SQLAREA
3 WHERE SQL_ID = '95smyj0461xrw';
SQL_TEXT INVALIDATIONS
SYSTEM @ XXXXX> select SYS.dbms_metadata.get_ddl( 'TABLE', 'JHLEE68_LCO_TEST_20160408' ) from dual;
SYS.DBMS_METADATA.GET_DDL('TABLE','JHLEE68_LCO_TEST_20160408')
CREATE TABLE "SYSTEM"."JHLEE68_LCO_TEST_20160408"
( "NO" NUMBER,
"NAME" VARCHAR2(5),
"ETC" VARCHAR2(100),
"ETC2" VARCHAR2(100) DEFAULT 'Y' NOT NULL ENABLE
) PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255
NOCOMPRESS LOGGING
STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1
BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
TABLESPACE "SYSTEM"
SYSTEM @ XXXXX> -- 늘리기
SYSTEM @ XXXXX> ALTER TABLE JHLEE68_LCO_TEST_20160408 MODIFY NAME VARCHAR2(10);
테이블이 변경되었습니다.
SYSTEM @ XXXXX> @LCO_CH3
SQL_ID PARSE_CALLS LOADS EXECUTIONS INVALIDATIONS RELOADS
SYSTEM @ XXXXX>
SYSTEM @ XXXXX> COL SQL_TEXT FOR A100
SYSTEM @ XXXXX> SELECT SQL_TEXT, INVALIDATIONS
2 FROM V$SQLAREA
3 WHERE SQL_ID = '95smyj0461xrw';
SQL_TEXT INVALIDATIONS
SYSTEM @ XXXXX> SELECT /* CURSOR_TEST3 */ * FROM JHLEE68_LCO_TEST_20160408 WHERE NO = 1;
NO NAME ETC ETC2
SYSTEM @ XXXXX> @LCO_CH3
SQL_ID PARSE_CALLS LOADS EXECUTIONS INVALIDATIONS RELOADS
SYSTEM @ XXXXX>
SYSTEM @ XXXXX> COL SQL_TEXT FOR A100
SYSTEM @ XXXXX> SELECT SQL_TEXT, INVALIDATIONS
2 FROM V$SQLAREA
3 WHERE SQL_ID = '95smyj0461xrw';
SQL_TEXT INVALIDATIONS
SYSTEM @ XXXXX>
h3. (3) Child 커서를 공유하지 못하는 경우
* 1. SQL에서 참조하는 오브젝트명이 같지만 SQL을 실행한 사용자에 따른 다른 오브젝트 가리킬 때
* 2. 참조 오브젝트가 변경돼 커서가 무효화되면 이후 그 커서를 처음 사용하려는 세션에 의해 다시 하드 파싱돼야 하는데, 특정
세션이 아직 기존 커서를 사용 중(Pin) 일 때
* 3. 옵티마이저 모드를 비롯해 옵티마이저 관련 파리미터가 다를 때
* 4. 입력된 바인드 값의 길이가 크게 다를 때
* 5. NLS 파라미터를 다르게 설정했을 때
* 6. SQL 트레이스를 활성화했을 때
{code:sql}
-- 다른 테이블 경우
SYS @ XXXXX> conn system/XXXXX@XXXXX
연결되었습니다.
SYSTEM @ XXXXX>
SYSTEM @ XXXXX>
SYSTEM @ XXXXX> CREATE TABLE SYSTEM.JHLEE68_LCO_TEST_20160415 AS
2 SELECT LEVEL NO, CHR( LEVEL ) NAME
3 FROM DUAL
4 CONNECT BY LEVEL <= 100;
테이블이 생성되었습니다.
SYSTEM @ XXXXX> SELECT /* CHILE_TEST4 */ * FROM JHLEE68_LCO_TEST_20160415 WHERE ROWNUM <= 1;
NO NAME
------ ----------
1
SYSTEM @ XXXXX> SELECT SQL_TEXT, SQL_ID
2 FROM V$SQL
3 WHERE 1 = 1 --
4 AND SQL_TEXT LIKE '%CHILE_TEST4%';
SQL_TEXT SQL_ID
---------------------------------------------------------------------------------------------------- -------------
SELECT SQL_TEXT, SQL_ID FROM V$SQL WHERE 1 = 1 -- AND SQL_TEXT LIKE '%CHILE_TEST4%' bdbdqz1r8t95q
SELECT /* CHILE_TEST4 */ * FROM JHLEE68_LCO_TEST_20160415 WHERE ROWNUM <= 1 awruqkrw87sy8
SYSTEM @ XXXXX>
SYSTEM @ XXXXX> SELECT sql_id, child_number, optimizer_mode, address, hash_value, parsing_user_id
2 FROM V$SQL
3 WHERE SQL_TEXT LIKE '%CHILE_TEST4%'
4 AND SQL_TEXT NOT LIKE '%V$SQL%'
5 AND SQL_ID = 'awruqkrw87sy8';
SQL_ID CHILD_NUMBER OPTIMIZER_ ADDRESS HASH_VALUE PARSING_USER_ID
------------- ------------ ---------- ---------------- ---------- ---------------
awruqkrw87sy8 0 FIRST_ROWS 07000100F874B648 4169393096 5
SYSTEM @ XXXXX>
SYSTEM @ XXXXX>
SYSTEM @ XXXXX> conn sys/XXXXX@XXXXX as sysdba
연결되었습니다.
SYS @ XXXXX> CREATE TABLE SYS.JHLEE68_LCO_TEST_20160415 AS
2 SELECT LEVEL NO, CHR( LEVEL ) NAME
3 FROM DUAL
4 CONNECT BY LEVEL <= 100;
테이블이 생성되었습니다.
SYS @ XXXXX> SELECT /* CHILE_TEST4 */ * FROM JHLEE68_LCO_TEST_20160415 WHERE ROWNUM <= 1;
NO NAME
------ ----------
1
SYS @ XXXXX> SELECT sql_id, child_number, optimizer_mode, address, hash_value, parsing_user_id
2 FROM V$SQL
3 WHERE SQL_TEXT LIKE '%CHILE_TEST4%'
4 AND SQL_TEXT NOT LIKE '%V$SQL%';
SQL_ID CHILD_NUMBER OPTIMIZER_ ADDRESS HASH_VALUE PARSING_USER_ID
------------- ------------ ---------- ---------------- ---------- ---------------
awruqkrw87sy8 0 FIRST_ROWS 07000100F874B648 4169393096 5
awruqkrw87sy8 1 FIRST_ROWS 07000100F874B648 4169393096 0
SYS @ XXXXX> SELECT sql_id, version_count, optimizer_mode, address, hash_value
2 FROM V$SQLAREA
3 WHERE SQL_TEXT LIKE '%CHILE_TEST4%'
4 AND SQL_TEXT NOT LIKE '%V$SQL%'
5 ;
SQL_ID VERSION_COUNT OPTIMIZER_ ADDRESS HASH_VALUE
------------- ------------- ---------- ---------------- ----------
awruqkrw87sy8 2 FIRST_ROWS 07000100F874B648 4169393096
SYS @ XXXXX>
-- 같은 테이블일 경우
SYS @ xxxxxx> conn system/xxxxxx@xxxxxx
연결되었습니다.
SYSTEM @ xxxxxx>
SYSTEM @ xxxxxx>
SYSTEM @ xxxxxx>
SYSTEM @ xxxxxx>
SYSTEM @ xxxxxx>
SYSTEM @ xxxxxx> SELECT /* CHILE_TEST5 */ * FROM SYS.JHLEE68_LCO_TEST_20160415 WHERE ROWNUM <= 1;
NO NAME
------ ----------
1
SYSTEM @ xxxxxx> SELECT sql_id, child_number, optimizer_mode, address, hash_value, parsing_user_id
2 FROM V$SQL
3 WHERE SQL_TEXT LIKE '%CHILE_TEST5%'
4 AND SQL_TEXT NOT LIKE '%V$SQL%';
SQL_ID CHILD_NUMBER OPTIMIZER_ ADDRESS HASH_VALUE PARSING_USER_ID
------------- ------------ ---------- ---------------- ---------- ---------------
493havd3rxym4 0 FIRST_ROWS 070001010CB34EB0 1199503972 5
SYSTEM @ xxxxxx>
@ > conn sys/xxxxxx@xxxxxx as sysdba
연결되었습니다.
SYS @ xxxxxx> SELECT /* CHILE_TEST5 */ * FROM SYS.JHLEE68_LCO_TEST_20160415 WHERE ROWNUM <= 1;
NO NAME
------ ----------
1
SYS @ xxxxxx> SELECT sql_id, child_number, optimizer_mode, address, hash_value, parsing_user_id
2 FROM V$SQL
3 WHERE SQL_TEXT LIKE '%CHILE_TEST5%'
4 AND SQL_TEXT NOT LIKE '%V$SQL%';
SQL_ID CHILD_NUMBER OPTIMIZER_ ADDRESS HASH_VALUE PARSING_USER_ID
------------- ------------ ---------- ---------------- ---------- ---------------
493havd3rxym4 0 FIRST_ROWS 070001010CB34EB0 1199503972 5
SYS @ xxxxxx> SELECT sql_id, version_count, optimizer_mode, address, hash_value
2 FROM V$SQLAREA
3 WHERE SQL_TEXT LIKE '%CHILE_TEST5%'
4 AND SQL_TEXT NOT LIKE '%V$SQL%';
SQL_ID VERSION_COUNT OPTIMIZER_ ADDRESS HASH_VALUE
------------- ------------- ---------- ---------------- ----------
493havd3rxym4 1 FIRST_ROWS 070001010CB34EB0 1199503972
SYS @ xxxxxx>
-- 같은 테이블 시노님 경우
SYSTEM @ XXXXX> conn system/XXXXX@XXXXX;
연결되었습니다.
SYSTEM @ XXXXX> SELECT /* CHILE_TEST3 */ * FROM DUAL;
D
-
X
SYSTEM @ XXXXX> SELECT SQL_TEXT, SQL_ID
2 FROM V$SQL
3 WHERE 1 = 1 --
4 AND SQL_TEXT LIKE '%CHILE_TEST3%';
SQL_TEXT SQL_ID
---------------------------------------------------------------------------------------------------- -------------
SELECT SQL_TEXT FROM V$SQL WHERE 1 = 1 -- AND SQL_TEXT LIKE '%CHILE_TEST3%' d9n0awq1f43wc
SELECT SQL_TEXT, SQL_ID FROM V$SQL WHERE 1 = 1 -- AND SQL_TEXT LIKE '%CHILE_TEST3%' 50bycrda19sg5
SELECT /* CHILE_TEST3 */ * FROM DUAL f14d3f8uwbg3j
SYSTEM @ XXXXX> SELECT sql_id, child_number, optimizer_mode, address, hash_value, parsing_user_id
2 FROM V$SQL
3 WHERE SQL_TEXT LIKE '%CHILE_TEST3%'
4 AND SQL_TEXT NOT LIKE '%V$SQL%'
5 AND SQL_ID = 'f14d3f8uwbg3j';
SQL_ID CHILD_NUMBER OPTIMIZER_ ADDRESS HASH_VALUE PARSING_USER_ID
------------- ------------ ---------- ---------------- ---------- ---------------
f14d3f8uwbg3j 0 FIRST_ROWS 07000101046A3758 902151281 5
SYSTEM @ XXXXX>
SYSTEM @ XXXXX> conn sys/XXXXX@XXXXX as sysdba
연결되었습니다.
SYS @ XXXXX>
SYS @ XXXXX> SELECT /* CHILE_TEST3 */ * FROM DUAL;
D
-
X
SYS @ XXXXX> SELECT sql_id, child_number, optimizer_mode, address, hash_value, parsing_user_id
2 FROM V$SQL
3 WHERE SQL_TEXT LIKE '%CHILE_TEST3%'
4 AND SQL_TEXT NOT LIKE '%V$SQL%'
5 AND SQL_ID = 'f14d3f8uwbg3j';
SQL_ID CHILD_NUMBER OPTIMIZER_ ADDRESS HASH_VALUE PARSING_USER_ID
------------- ------------ ---------- ---------------- ---------- ---------------
f14d3f8uwbg3j 0 FIRST_ROWS 07000101046A3758 902151281 5
SYS @ XXXXX>
SYS @ XXXXX> SELECT sql_id, version_count, optimizer_mode, address, hash_value
2 FROM V$SQLAREA
3 WHERE SQL_TEXT LIKE '%CHILE_TEST3%'
4 AND SQL_TEXT NOT LIKE '%V$SQL%'
5 AND SQL_ID = 'f14d3f8uwbg3j' ;
SQL_ID VERSION_COUNT OPTIMIZER_ ADDRESS HASH_VALUE
------------- ------------- ---------- ---------------- ----------
f14d3f8uwbg3j 1 FIRST_ROWS 07000101046A3758 902151281
SYS @ XXXXX> SELECT USERNAME
2 FROM DBA_USERS
3 WHERE USER_ID = 5
4 ;
USERNAME
------------------------------
SYSTEM
SYS @ XXXXX>
SYS @ xxxxxx> create table jhlee68_card_test_20160415
2 as
3 select level no from dual connect by level <= 1000;
테이블이 생성되었습니다.
SYS @ xxxxxx> analyze table jhlee68_card_test_20160415 compute statistics for table for all columns;
테이블이 분석되었습니다.
SYS @ xxxxxx> explain plan for select * from jhlee68_card_test_20160415 where no <= :no;
해석되었습니다.
SYS @ xxxxxx>
SYS @ xxxxxx>
SYS @ xxxxxx> select * from table( dbms_xplan.display( null, null, 'basic rows'));
----------------------------------------------------------------
| Id | Operation | Name | Rows |
----------------------------------------------------------------
| 0 | SELECT STATEMENT | | 10 |
| 1 | TABLE ACCESS FULL| JHLEE68_CARD_TEST_20160415 | 10 |
----------------------------------------------------------------
8 개의 행이 선택되었습니다.
SYS @ xxxxxx> explain plan for select * from jhlee68_card_test_20160415 where no between :no1 and :no2;
해석되었습니다.
SYS @ xxxxxx> select * from table( dbms_xplan.display( null, null, 'basic rows'));
-----------------------------------------------------------------
| Id | Operation | Name | Rows |
-----------------------------------------------------------------
| 0 | SELECT STATEMENT | | 3 |
| 1 | FILTER | | |
| 2 | TABLE ACCESS FULL| JHLEE68_CARD_TEST_20160415 | 3 |
-----------------------------------------------------------------
9 개의 행이 선택되었습니다.
-- 리터널 변수
SYS @ xxxxxx> explain plan for select * from jhlee68_card_test_20160415 where no <= 100;
해석되었습니다.
SYS @ xxxxxx> select * from table( dbms_xplan.display( null, null, 'basic rows'));
----------------------------------------------------------------
| Id | Operation | Name | Rows |
----------------------------------------------------------------
| 0 | SELECT STATEMENT | | 11 |
| 1 | TABLE ACCESS FULL| JHLEE68_CARD_TEST_20160415 | 11 |
----------------------------------------------------------------
8 개의 행이 선택되었습니다.
SYS @ xxxxxx> explain plan for select * from jhlee68_card_test_20160415 where no between 500 and 600;
해석되었습니다.
SYS @ xxxxxx> select * from table( dbms_xplan.display( null, null, 'basic rows'));
----------------------------------------------------------------
| Id | Operation | Name | Rows |
----------------------------------------------------------------
| 0 | SELECT STATEMENT | | 11 |
| 1 | TABLE ACCESS FULL| JHLEE68_CARD_TEST_20160415 | 11 |
----------------------------------------------------------------
8 개의 행이 선택되었습니다.
SYS @ xxxxxx>
SELECT /*+ FULL( a ) */ *
FROM 아파트매물 a
WHERE :CITY IN ( '서울시','경기도' )
AND 도시 = :CITY
UNION ALL
SELECT /*+ INDEX( a IDX01 ) */ *
FROM 아파트매물 a
WHERE :CITY NOT IN ( '서울시','경기도' )
AND 도시 = :CITY
SELECT /*+ FULL( EMP ) */ * FROM EMP
WHERE :deptno = '30'
AND DEPTNO = :deptno
UNION ALL
SELECT /*+ FULL( EMP ) */ * FROM EMP
WHERE :deptno <> '30'
AND DEPTNO = :deptno
Rows Row Source Operation
----- --------------------------------------------
0 STATEMENT
3 UNION-ALL (cr=4 pr=0 pw=0 time=151 us)
0 FILTER (cr=0 pr=0 pw=0 time=9 us)
0 TABLE ACCESS FULL EMP (cr=0 pr=0 pw=0 time=0 us)
3 FILTER (cr=0 pr=0 pw=0 time=85 us)
3 TABLE ACCESS BY INDEX ROWID EMP (cr=0 pr=0 pw=0 time=47 us)
3 INDEX RANGE SCAN EMP_DEPTNO_IDX (cr=2 pr=0 pw=0 time=49 us)
-- 개발단 로직에서 분할
IF :CITY IN ( '서울시', '경기도' ) THEN
SELECT /*+ FULL( A ) */ *
FROM 아파트매물 A
WHERE 도시 = :CITY;
ELSE
SELECT /*+ INDEX( A IDX01 ) */ *
FROM 아파트매물 A
WHERE 도시 = :CITY;
END IF;
SYSTEM @ xxxx> create table jhlee68_server_test( x number );
테이블이 생성되었습니다.
SYSTEM @ xxxx> col name for a30
SYSTEM @ xxxx> SELECT A.NAME, B.VALUE
2 FROM v$statname a, v$mystat b
3 WHERE A.NAME IN ( 'session cursor cache hits', 'parse count (total)')
4 AND B.STATISTIC# = A.STATISTIC#;
NAME VALUE
------------------------------ ----------
session cursor cache hits 180
parse count (total) 180
SYSTEM @ xxxx> alter session set session_cached_cursors = 0;
세션이 변경되었습니다.
SYSTEM @ xxxx> declare
2 i number;
3 begin
4 for i in 1..10000
5 loop
6 execute immediate 'insert into jhlee68_server_test values( ' ||mod( i,100 ) ||')';
7 end loop;
8 commit;
9 end;
10 /
PL/SQL 처리가 정상적으로 완료되었습니다.
SYSTEM @ xxxx> col name for a30
SYSTEM @ xxxx> SELECT A.NAME, B.VALUE
2 FROM v$statname a, v$mystat b
3 WHERE A.NAME IN ( 'session cursor cache hits', 'parse count (total)')
4 AND B.STATISTIC# = A.STATISTIC# ;
NAME VALUE
------------------------------ ----------
session cursor cache hits 180
parse count (total) 10195
SYSTEM @ xxxx> alter session set session_cached_cursors = 100;
세션이 변경되었습니다.
SYSTEM @ xxxx> declare
2 i number;
3 begin
4 for i in 1..10000
5 loop
6 execute immediate 'insert into jhlee68_server_test values( ' ||mod( i,100 ) ||')';
7 end loop;
8 commit;
9 end;
10 /
PL/SQL 처리가 정상적으로 완료되었습니다.
SYSTEM @ xxxx> col name for a30
SYSTEM @ xxxx> SELECT A.NAME, B.VALUE
2 FROM v$statname a, v$mystat b
3 WHERE A.NAME IN ( 'session cursor cache hits', 'parse count (total)')
4 AND B.STATISTIC# = A.STATISTIC#
5 ;
NAME VALUE
------------------------------ ----------
session cursor cache hits 180
parse count (total) 20200
SYSTEM @ xxxx> select sql_fulltext
2 from v$sql
3 where sql_text like 'insert into jhlee68_server_test%'
4 and rownum <= 10
5 ;
SQL_FULLTEXT
--------------------------------------------------------------------------------
insert into jhlee68_server_test values( 23)
insert into jhlee68_server_test values( 25)
insert into jhlee68_server_test values( 30)
insert into jhlee68_server_test values( 51)
insert into jhlee68_server_test values( 60)
insert into jhlee68_server_test values( 50)
insert into jhlee68_server_test values( 67)
insert into jhlee68_server_test values( 61)
insert into jhlee68_server_test values( 98)
insert into jhlee68_server_test values( 83)
10 개의 행이 선택되었습니다.
SYSTEM @ xxxx> select a.value "session cursor chche hits"
2 , b.value "total parse call count"
3 , round(a.value/b.value*100,2) "session cursor cache hits"
4 from v$sysstat a, v$sysstat b
5 where a.name = 'session cursor cache hits'
6 and b.name = 'parse count (total)';
session cursor chche hits total parse call count session cursor cache hits
------------------------- ---------------------- -------------------------
127161883 214443641 59.3
SYSTEM @ xxxx> disconn
Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production
With the Partitioning, Real Application Clusters and Real Application Testing options에서 분리되었습니다.
@ >
@ > conn system/xxxx@xxxx
연결되었습니다.
SYSTEM @ xxxx>
SYSTEM @ xxxx> col name for a30
SYSTEM @ xxxx> SELECT A.NAME, B.VALUE
2 FROM v$statname a, v$mystat b
3 WHERE A.NAME IN ( 'session cursor cache hits', 'parse count (total)')
4 AND B.STATISTIC# = A.STATISTIC#;
NAME VALUE
------------------------------ ----------
session cursor cache hits 1
parse count (total) 11
SYSTEM @ xxxx> alter session set session_cached_cursors = 0;
세션이 변경되었습니다.
SYSTEM @ xxxx> declare
2 var number;
3 sql_stmt varchar2( 1000 );
4 begin
5 for i in 1..10000
6 loop
7 var := mod( i,100 );
8 sql_stmt := 'insert into jhlee68_server_test values( :1 )';
9 execute immediate sql_stmt using var;
10 end loop;
11 commit;
12 end;
13 /
PL/SQL 처리가 정상적으로 완료되었습니다.
SYSTEM @ xxxx> col name for a30
SYSTEM @ xxxx> SELECT A.NAME, B.VALUE
2 FROM v$statname a, v$mystat b
3 WHERE A.NAME IN ( 'session cursor cache hits', 'parse count (total)')
4 AND B.STATISTIC# = A.STATISTIC#
5 ;
NAME VALUE
------------------------------ ----------
session cursor cache hits 1
parse count (total) 10022
SYSTEM @ xxxx> alter session set session_cached_cursors = 100;
세션이 변경되었습니다.
SYSTEM @ xxxx> declare
2 var number;
3 sql_stmt varchar2( 1000 );
4 begin
5 for i in 1..10000
6 loop
7 var := mod( i,100 );
8 sql_stmt := 'insert into jhlee68_server_test values( :1 )';
9 execute immediate sql_stmt using var;
10 end loop;
11 commit;
12 end;
13 /
PL/SQL 처리가 정상적으로 완료되었습니다.
SYSTEM @ xxxx> col name for a30
SYSTEM @ xxxx> SELECT A.NAME, B.VALUE
2 FROM v$statname a, v$mystat b
3 WHERE A.NAME IN ( 'session cursor cache hits', 'parse count (total)')
4 AND B.STATISTIC# = A.STATISTIC#
5 ;
NAME VALUE
------------------------------ ----------
session cursor cache hits 10000
parse count (total) 10027
SYSTEM @ xxxx> select a.value "session cursor chche hits"
2 , b.value "total parse call count"
3 , round(a.value/b.value*100,2) "session cursor cache hits"
4 from v$sysstat a, v$sysstat b
5 where a.name = 'session cursor cache hits'
6 and b.name = 'parse count (total)';
session cursor chche hits total parse call count session cursor cache hits
------------------------- ---------------------- -------------------------
127114092 214465659 59.27
SYSTEM @ xxxx> select * from v$version;
BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production
PL/SQL Release 11.2.0.4.0 - Production
CORE 11.2.0.4.0 Production
TNS for IBM/AIX RISC System/6000: Version 11.2.0.4.0 - Production
NLSRTL Version 11.2.0.4.0 - Production
SYSTEM @ xxxx>
-- Pro*C
for(;;){
EXEC ORACLE OPTION( HOLD_CURSOR=YES ); -- 어플리케이션 커서와 세션 커서의 관계를 다룬다.
EXEC ORACLE OPTION( RELEASE_CURSOR=NO ); -- 공유 커서와 세션 커서 관계를 다룬다.
EXEC SQL INSERT ....;
EXEC ORACLE OPTION( RELEASE_CURSOR=YES );
}
public class ParseCall
{
public static void NoBinding ( Connection onn, int count ) throws Exception{
PaeparedStatement stmt;
ResultSet rs;
for ( int i = 1; i <= count; i++ ){
stmt = conn.prepareStatement(
"select /* no_binding */ " + i + "," + ",'test', a.* " +
"from emp a where e.ename like 'W%'");
rs=stmt.executeQuery();
rs.close();
stmt.close();
}
}
}
h3. (2) 바인드 변수를 사용하지만, 커서를 캐싱하지 않을 때
{code:sql}
public class ParseCall
{
public static void NoCaching ( Connection onn, int count ) throws Exception{
PaeparedStatement stmt;
ResultSet rs;
for ( int i = 1; i <= count; i++ ){
stmt = conn.prepareStatement(
"select /* no_caching */ " ?,?,?,a.* " +
"from emp a where e.ename like 'W%'");
stmt.setInt( 1, i );
stmt.setInt( 2, i );
stmt.setString( 3, "test" );
rs=stmt.executeQuery();
rs.close();
stmt.close();
}
}
}
public class ParseCall
{
public static void CursorHolding ( Connection onn, int count ) throws Exception{
// 루프문 바깥에 선언
PaeparedStatement stmt = conn.prepareStatement(
"select /* no_caching */ " ?,?,?,a.* " +
"from emp a where e.ename like 'W%'");
ResultSet rs;
for ( int i = 1; i <= count; i++ ){
stmt = conn.prepareStatement(
"select /* no_caching */ " ?,?,?,a.* " +
"from emp a where e.ename like 'W%'");
stmt.setInt( 1, i );
stmt.setInt( 2, i );
stmt.setString( 3, "test" );
rs=stmt.executeQuery();
rs.close();
}
// 루프문 빠져 나왔을 때 커서를 닫는다.
stmt.close();
}
}
public class ParseCall
{
public static void CursorCaching ( Connection onn, int count ) throws Exception{
// 캐시 사이즈를 1로 지정
((OracleConnection)conn).setStatementCacheSize(1);
// 묵시적 캐싱 기능을 활성화
((OracleConnection)conn).setImplicitCachingEnabled(true);
for ( int i = 1; i <= count; i++ ){
PaeparedStatement stmt = conn.prepareStatement(
"select /* no_caching */ " ?,?,?,a.* " +
"from emp a where e.ename like 'W%'");
stmt.setInt( 1, i );
stmt.setInt( 2, i );
stmt.setString( 3, "test" );
ResultSet rs=stmt.executeQuery();
rs.close();
// 커서를 닫지만 내부적으로 닫히지 않은 채 캐시에 보관
stmt.close();
}
}
}
public static void main( Straing[] args ) throws Exception{
//Bind 변수를 사용하지 않았을 대
NoBinding( conn, 5000 );
...
// Bind 변수를 사용하지만 Caching 옵션을 사용하지 않을 때
NoCaching( conn, 5000 );
...
// Cursor를 닫지 않고 반복적으로 재사용할 때
CursorHolding( conn, 5000 );
...
// Caching 옵션을 사용할 때
CursorCaching( conn, 5000 );
}
-- Pro*C
int main()
{
printf( "사번을 입력하십시오 : ");
scanf("%d", &empno);
EXEC SQL WHENEVER NOT FOUND GOT notfound;
EXEC SQL SELECT ENAME INTO :ENAME
FROM EMP
WHERE EMPNO = :empno;
printf( "사원명 : %s.\n", ename);
notfound:
printf("%d는 존재하지 않는 사번입니다.\n", empno );
}
-- Prc*C
-- test.pc
EXEC SQL INCLUDE SQLCA.H;
int main()
{
EXEC SQL
UPDATE EMP SET SAL = SAL * 1.1
WHER EMPNOO = 7900;
RETURN 0;
}
$ proc test.pc sqlcheck=syntax
-- Prc*C
-- test.pc
EXEC SQL INCLUDE SQLCA.H;
int main()
{
EXEC SQL
UPDATE EMPs SET SAL = SAL * 1.1
WHERE EMPNOO = 7900;
RETURN 0;
}
$ proc test.pc sqlcheck=syntax -- Success!!
$ proc test.pc sqlcheck=full userid=scott/tiger -- Error!! 유효 오브젝트 및 액세스 권한까지 체크
-- JAVA
PreparedStatment stmt;
ResultSet rs;
StringBuffer SQLStmt = new StringBuffer();
SQLStmt.append( "SELECT ENAME, SAL FROM EMP " );
SQLStmt.append( "WHERE EMPNO = ? " );
stmt = conn.prepareStatement( SQLStmt.toString() );
stmt.setLong( 1, txtEmpno.value );
rs = stmt.executeQuery();
// do anything
rs.close();
stmt.close();
-- Delphi
begin
Query1.Close;
Query1.Sql.Clear;
Query1.Sql.Add( 'SELECT ENAME, SAL FROM EMP ');
Query1.Sql.Add( 'WHERE EMPNO = :empno');
Query1.ParamByName( 'empno').AsString := txtEmpno.Text;
Query1.Open;
end;
-- Visual Basic
Dim conn As NEW ADODB.Command
Dim rs As ADODB.Recordset
DIM SQLStmt as String
SQLStmt = "SELECT ENAME, SAL FROM EMP"
SQLSTMT = SQLStmt & "WHERE EMPNO = ? "
comm.CommandText = SQLStmt
comm.Parameters.Append comm.CreateParameter( "empno", adNumeric, adParamInput );
comm.Parameters( "empno" ).Value = txtEmpno.Text
Set Rs = Comm.Execute
' do anything
rs.Close
Set rs = Nothing
Set comm = Nothing