SQL 의 이해

1. SQL 의 이해


UPDATE T1
SET     SMALL_NO = SMALL_NO + 0.1
WHERE  ID = 3
AND    SMALL_NO = 1

1.1 Parsing - 문장의 의미 이해

  1. Optimizing - 문장을 실행하기 위한 최선의 방법 찾기
  2. 파싱 = Syntactic(구문) 분석 + Semantic(의미) 분석
    1. Syntactic(구문) 분석 SQL 문이 유효한지 결정
    2. Semantic(의미) 분석
      1. T1 의 오브젝트유형은 무엇인가? 테이블, 뷰, 시노님 등
      2. T1 오브젝트에 ID 와 SMALL_NO 칼럼이 존재 하는가 ?
      3. SMALL_NO 칼럼에 UPDATE 시 체크해야 할 제약조건이 존재 하는가 ?
      4. 해당 오브젝트에 UPDATE 시 수행되야 할 트리거가존재하는가 ?
      5. 오브젝트가 UPDATE 될 때 관리돼야 할 인덱스가 존재하는가?
      6. 해당 유저가 오브젝트를 UPDATE 할 권한을 가지고 있는가 ?

Rules of syntax specify how language elements are sequenced to form valid statements.

Thus, syntactic checking verifies that keywords, object names, operators, delimiters,
and so on are placed correctly in your SQL statement. For example, the following embedded SQL statements contain syntax errors:

EXEC SQL DELETE FROM EMP WHER DEPTNO = 20;
– misspelled keyword WHERE
EXEC SQL INSERT INTO ( EMP COMM, SAL ) VALUES (NULL, 1500);
– missing parentheses around column names COMM and SAL

Rules of semantics specify how valid external references are made.
Thus, semantic checking verifies that references to database objects
and host variables are valid and that host variable datatypes are correct.
For example, the following embedded SQL statements contain semantic errors:

EXEC SQL DELETE FROM empp WHERE deptno = 20;
-- nonexistent table, EMPP
EXEC SQL SELECT * FROM emp WHERE ename= :emp_name;
-- undeclared host variable, emp_name

1.2 최적화

  1. ID 또는 SMALL_NO(또는 양쪽) 컬럼에 인덱스가 존재하고 , 도움이 되는가?
  2. 테이블, 인덱스 및 칼럼에 대한 통계정보가 존재하는가 ?

SQL> create table t1 ( id number, small_no number ) ;
Table created.
SQL> exec dbms_stats.gather_table_stats(user,'T1');
PL/SQL procedure successfully completed.

SQL> alter system flush shared_pool ;
System altered.
--	이전 SQL 문장의 라이브러리 캐시로부터 제거
--	오브젝트에 대한 권한 및 종속성, 오브젝트 정의를 딕셔네리 캐시로부터 제거
SQL> alter session set sql_trace = true ;
Session altered.

SQL> update t1 set small_no = small_no + 0.1
2  where id = 3 and small_no = 1 ;
0 rows updated.

SQL> alter session set sql_trace = false ;
Session altered.

1  session in tracefile.
2  user  SQL statements in trace file.
-- ( 유저가 수행한 1) alter session... 2) update 문장 )
13  internal SQL statements in trace file.
-- ( sys recursive 문장 : DBMS 가 Update 문을 이해(Parse) 및 최적화 수행)
15  SQL statements in trace file.
14  unique SQL statements in trace file.
175  lines in trace file.

  • 1차 테스트 TRACE 내용

OVERALL TOTALS FOR ALL RECURSIVE STATEMENTS

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse      15     0.01       0.00          0          0          0           0
Execute    99     0.06       0.05          0          0          0           0
Fetch     189     0.00       0.01          0        338          0         633
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Total     303     0.10       0.07          0        338          0         633

-- 15개의 SQL문에 대한 parsel call 15회 수행, execute call 99 회 수행, 
-- fetch call 189 회 수행을 통해서 633 Row 추출
Misses in library cache during parse: 15
--	Miss 발생은 자식 커서(실행계획)가 라이브러리 캐시 내에 존재 하지 않음 의미
--	Recursive SQL 문의 첫 번째 parse call 시에 최적화 필요함
Misses in library cache during execute: 15
--	During execute는 excute 단계에서, LCO Aging Out

  • 2차 테스트 TRACE 내용(테이블을 동일하게 생성 후 반복 수행 )

SQL> create table t1a ( id number, small_no number ) ;
Table created.

SQL> exec dbms_stats.gather_table_stats(user,'T1');
-- PL/SQL procedure successfully completed.
--	이후 동일한 테스트 수행 (Shared Pool Flush 하지 않는다.)
OVERALL TOTALS FOR ALL RECURSIVE STATEMENTS

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse       15      0.00       0.00          0          0          0           0
Execute     43      0.01       0.01          0          0          0           0
Fetch       51      0.00       0.00          0         135         0         526
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Total      109      0.00       0.00          0         133        0          526

Misses in library cache during parse: 0
--	1차 테스트와 동일한 Parse call= 15 발생
--	그러나, execute 와 fetch call 횟수가 다름
--	Miss 0 발생은 이미 적절한 커서가 라이브러리 캐시 내에 존재


  • 테스트 Tkprof 요약에 대한 해석

-- SQL 문장이 참조하는 Object 정의 찾는 Recursivce SQL
selectobj#,type#,ctime,mtime,stime,status,dataobj#,flags,oid$, spare1,
  spare2
from obj$ where owner#=:1 and name=:2 and namespace=:3 and remoteowner is null
andlinkname is null and subname is null
--  SQL 문장이 참조하는 테이블 정의 찾는 Recursivce SQL
select t.ts#,t.file#,t.block#,nvl(t.bobj#,0),nvl(t.tab#,0),t.intcols,
nvl(t.clucols,0),t.audit$,t.flags,t.pctfree$,t.pctused$,t.initrans,
  t.maxtrans,t.rowcnt,t.blkcnt,t.empcnt,t.avgspc,t.chncnt,t.avgrln,
t.analyzetime,t.samplesize,t.cols,t.property,nvl(t.degree,1),
nvl(t.instances,1),t.avgspc_flb,t.flbcnt,t.kernelcols,nvl(t.trigflag, 0),
  nvl(t.spare1,0),nvl(t.spare2,0),t.spare4,t.spare6,ts.cachedblk,ts.cachehit,
ts.logicalread
from tab$ t, tab_stats$ ts where t.obj#= :1 and t.obj# = ts.obj# (+)
-- SQL 문장이 참조하는 인덱스 정의 찾는 Recursivce SQL
select i.obj#,i.ts#,i.file#,i.block#,i.intcols,i.type#,i.flags,i.property,
  i.pctfree$,i.initrans,i.maxtrans,i.blevel,i.leafcnt,i.distkey,i.lblkkey,
  i.dblkkey,i.clufac,i.cols,i.analyzetime,i.samplesize,i.dataobj#,
  nvl(i.degree,1),nvl(i.instances,1),i.rowcnt,mod(i.pctthres$,256),
  i.indmethod#,i.trunccnt,nvl(c.unicols,0),nvl(c.deferrable#+c.valid#,0),
nvl(i.spare1,i.intcols),i.spare4,i.spare2,i.spare6,decode(i.pctthres$,null,
null,mod(trunc(i.pctthres$/256),256)),ist.cachedblk,ist.cachehit,
ist.logicalread
from ind$ i, ind_stats$ ist, (select enabled, min(cols) unicols,
  min(to_number(bitand(defer,1))) deferrable#,min(to_number(bitand(defer,4)))
valid# from cdef$ where obj#=:1 and enabled > 1 group by enabled) c where
i.	obj#=c.enabled(+) and i.obj# = ist.obj#(+) and i.bo#=:1 order by i.obj#
-- SQL 문장이 참조하는 칼럼 정의 찾는 Recursivce SQL
select name,intcol#,segcol#,type#,length,nvl(precision#,0),decode(type#,2,
  nvl(scale,-127/*MAXSB1MINAL*/),178,scale,179,scale,180,scale,181,scale,182,
  scale,183,scale,231,scale,0),null$,fixedstorage,nvl(deflength,0),default$,
rowid,col#,property, nvl(charsetid,0),nvl(charsetform,0),spare1,spare2,
nvl(spare3,0)
from col$ where obj#=:1 order by intcol#
-- 첫번째 테스트는 다양한 "bootstrap" 활동
-- ( 오라클은 테이블과 인텍스에 대한 정보를 확인하기 위해서, internal 테이블과 인텍스에
--  대한 몇 가지 정보를 더 확인할 필요가 있다. )
-- 두번째 테스트는 첫번째 테스트에서 캐시된 정보를 이용 (메타데이터와 코드의 캐싱을 의미함)
--   메타데이타 - row cache : 테이블, 인덱스, 칼럼, 히스토그램, 트리거 등과 같은 오브젝트 정보
--   코드 - 라이브러리 캐시 : 명령어(SQL문과 PL/SQL), 커서 및 오브젝트 종속성과 권한 정보

bootstraps
http://www.hankyung.com/news/app/newsview.php?aid=2013041992341

컴퓨터에 전원을 넣으면 마이크로소프트의 윈도와 같은 운영체제(Operating System)가 가장 먼저 실행되고,
그 이후에 실행되는 프로그램들은 모두 이 운영체제 위에서 작동된다.
이 때 처음 운영체제가 실행되는 것은 다른 프로그램의 도움 없이 스스로 실행된다는 점에서 가죽끈(bootstrap)을 잡아당겨 스스로 일을 해낸다는
표현 속의 boot를 이용하여 "boot up"이라고 표현하기 시작한 것이다.
컴퓨터가 boot up되고 나면 이제 여러분의 모니터엔 "바탕화면"이 나타난다.

분명한 것은 특정 SQL문을 수행할 때 까지는 어떤 SQL문도 수행하지 못한다는 것이다.
오라클 bootstrap 오브젝트는 $ORACLE_HOME/rdbms/admin/sql.bsq를 통해 확인 가능
해당 스크립트 내에는 sys.bootstrap$ 테이블 및 bootstrap 오브젝트를 재생성 SQL
예제)
create table tab$ /* table table */
( obj# number not null, /* object number */
...중략...
create table seg$ /* segment table */
( file# number not null, /* segment header file number */
block# number not null, /* segment header block number */
type# number not null, /* segment type (see KTS.H):
...

  • CURSOR
    {note}
  • 사용자 프로그램 관점
    : 커서는 일반적으로 결과 집합 의미, 라이브러리 캐시 내에 저장된 "실행 가능한" 명령어를 참조하는 배열의 인덱스이며, 사용자 프로그램 데이터와 라이브러리 캐시 정보를 연결하는 역할
  • 인스턴스 관점
    1. 명령어가 수행될 때 세션의 프로세스 메모리 내에 저장되는 일시적인 데이터 의미
    ( 상태에 대한 정보와 결과집합의 일부 포함)
    2. 라이브러리 캐시 내에 저장된 SQL 문의 실행 가능한 버전 의미
    3. 하나의 명령어(SQL)가 여러 개의 실행 계획 가질 때 발생
    Place-holder : parent cursor, 개별 실행 계획 - child cursor
    **[참고 Cursor 정보]
    ▶ Heap 0 ( Cursor 기본정보 )
    ▶ Heap 6 ( Cursor 실행계획정보 )
    ● DBMS_SHARED_POOL.KEEP 을 통한 CURSOR 를 KEEP 하여도,
    ALTER SYSTEM SHARED_POOL FLUSH 에 의해서 Invalid 상태로 됨( Flush됨 )
    ● SESSION_CACHED_CURSOR 값( 0 보다 큰 경우)에 의해서 Heap 0 정보가 pin 되고,
    heap 6 정보는 pin 되지 않는다. 또한 pin 된 Heap 0 정보는 Flush 되지 않는다.
    ( SESSION_CACHED_CURSOR 값이 지나치게 높은 경우, SESSION_CACHED_CURSOR 값에 의해서
    Heap 0 이 무더기로 pin 되고, 이에 의해서 Shared_Pool Fragmentation 이 발생할 수 가능 )