교육과정
SQL
PLSQL
Database Administration
Backup & Recovery
Performance Tuning
SQL Tuning
모든 오라클 프로세스가 액세스하는 공유 메모리
show sga
Total System Global Area 713027608 bytes <- sga_max_size
Fixed Size 8900632 bytes <- 오라클 알고리즘이 수행되는 공간
Variable Size 641728512 bytes
Database Buffers 54525952 bytes <- data buffer cache
Redo Buffers 7872512 bytes <- redo log buffer
select * from v$sgainfo;
NAME BYTES RES CON_ID
--------------------------------------------- ---------- --- ----------
Fixed SGA Size 8900632 No 0
Redo Buffers 7872512 No 0
Buffer Cache Size 54525952 Yes 0
In-Memory Area Size 0 No 0
Shared Pool Size 301989888 Yes 0
Large Pool Size 8388608 Yes 0
Java Pool Size 4194304 Yes 0
Streams Pool Size 8388608 Yes 0
Shared IO Pool Size 16777216 Yes 0
Data Transfer Cache Size 0 Yes 0
Granule Size 4194304 No 0
Maximum SGA Size 713027608 No 0
Startup overhead in Shared Pool 169104992 No 0
Free SGA Memory Available 318767104 0
select count(*) from v$sgastat where pool='shared pool';

select *
from (select name,bytes
from v$sgastat
where pool = 'shared pool'
order by bytes desc)
where rownum <= 30;
NAME BYTES
--------------------------------------------- ----------
SQLA 35879848
KGLH0 23629600
free memory 21845272
KGLS 16942368
ksunfy_meta 1 13015936
row cache mutex 9019032
SO private sga 7441712
PLMCD 7236760
private strands 7218176
KQR X PO 6748896
KGLHD 6366800
row cache hash 6012688
KGLSG 5260816
obj stats allocation chun 5160960
PLDIA 4986208
session 4985408
ASH buffers 4194304
kglsim hash table bkts 4194304
KTI-UNDO 4134000
KCB Table Scan Buffer 3981120
KSFD SGA I/O b 3977184
KSKQ master CG stats seg 3674680
ksipc state object 3447936
message pool freequeue 3051744
row cache mutex versions 3006344
KSRMA State Object 2587376
KKSSP 2428672
KGLDA 2418008
parameter table block 2338576
KTSL subheap 2097888
library cache = SQL로 시작하는 components들
data dictionary cache = row cache로 시작하는 components들
데이터 처리방법
1) rowid scan
- by user rowid
- by index rowid
2) full table scan
조인방법
1) nested loop
2) sort merge
3) hash
조인 순서
1) from절에 나열되어 있는 테이블의 갯수만큼 순서를 결정해야 한다.
2) 만약 조인 수행해야할 테이블의 갯수가 3개면 3! 경우수 만큼 결정
예) from a,b,c = (a,b,c),(a,c,b),(b,a,c),(b,c,a),(c,a,b),(c,b,a)
1) 문법체크(syntax), 의미분석(semantic)체크, 권한(privilege)체크
2) soft parsing
library cache latch(mutex)를 잡고 검색해야 한다.latch : library cache(9i) wait event 발생한다.library cache : mutex x(10g) wait event 발생한다.3) hard parsing
soft parsing이 실패 즉 동일한 SQL문이 shared pool 메모리안에 library cache에 존재하지 않습니다.
메모리 공간 확보
shared pool latch를 잡고 적절한 크기의 free chunk를 free list에서 찾는다.
예)
free list안에 free chunk가 7k,10k,1k,100byte 이렇게 나있을 경우 내가 필요한 프리 공간은 8k 프리 공간이 필요할 경우 프리로 있는 10k 프리 공간을 8k로 확보하고, 남은 2k는 프리 공간으로 남겨 놓는다. 이제 남은 프리 청크는 7k, 2k, 1k, 100byte로 구성된다.그다음에 또 내가 필요한 프리 공간이 8k일 경우 , 즉 내가 필요한 프리 청크가 없을 경우 오류가 발생한다. ORA-04031 오류 발생.
오류를 해결할 수 있는 현재 유일한 방법은 shared_pool 공간을 flush 해줘야 한다.
프리청크를 찾기 위해서 latch를 잡아야하는데 못잡으면
latch : shared pool wait event 발생한다.
프리를 확보한 후 LCO(Library Cache Object)를 생성해야한다.
library cache lock(exclusive) 획득해야한다. 그래야 다른 세션이 생성중인 LCO를 참조할 수 없다.library cache lock(NULL) 모드로 변환된다.library cache pin를 exclusive 모드로 획득한 후 실행계획을 새롭게 생성해야 한다.
LCO는 |SQL문/PLSQL문|parse된 code|실행계획|으로 이루어져 있고, LCO의 문패는 SQL문이다.
library cache lock 과 library cache pin을 shared 모드로 변환하고 SQL문을 실행한다.library cache lock을 null 모드로 변환하고 library cache pin을 해제한다.shared pool flush
- shared pool의 library cache에 있는 LOC가 전부 삭제된다.
alter system flush shared_pool;
shared pool을 flush 해놓은 상태이기 때문에 조회되는 LCO는 없다.
select sql_id, sql_text, parse_calls, loads, executions
from v$sql
where sql_text like '%hr.employees%'
and sql_text not like '%v$sql%';

select * from hr.employees where employee_id=100;
select sql_id, sql_text, parse_calls, loads, executions
from v$sql
where sql_text like '%hr.employees%'
and sql_text not like '%v$sql%';

select * from hr.employees where employee_id=100;
select * from hr.employees where employee_id=101;
select * from hr.employees where employee_id=102;
select * from hr.employees where employee_id=103;
select * from hr.employees where employee_id=104;
select * from hr.employees where employee_id=105;
select sql_id, sql_text, parse_calls, loads, executions
from v$sql
where sql_text like '%hr.employees%'
and sql_text not like '%v$sql%';

select * from table(dbms_xplan.display_cursor('6z02qx94wmk10'));
select * from table(dbms_xplan.display_cursor('2d3pkrknvggfd'));
select sql_id, sql_text, parse_calls, loads, executions,hash_value, plan_hash_value
from v$sql
where sql_text like '%hr.employees%'
and sql_text not like '%v$sql%';

plan_hash_value가 동일하다는 것은 실행계획이 같다는 것이기 때문에 실행계획을 공유 시켜줄 필요가 있다.
drop table hr.emp purge;
create table hr.emp as select * from hr.employees;
alter system flush shared_pool;
select * from hr.emp where employee_id = 100;

select sql_id, sql_text, parse_calls, loads, executions,invalidations
from v$sql
where sql_text like '%hr.emp%'
and sql_text not like '%v$sql%';

select * from table(dbms_xplan.display_cursor('5g6ygund8wa94'));

- filter로 검색 : 데이터가 어느 블록에 있는지 알 수 없어, 모든 블록을 다 찾는다.
- 실행계획을 만들기 위해서는 통계정보가 필요한데 처음 테이블을 만들었을때는 통계정보가 없지만 dynamic 샘플 표본을 통해 실행계획을 생성한다.
select num_rows, blocks, avg_row_len from dba_tables where owner='HR' and table_name='EMP';

execute dbms_stats.gather_table_stats('hr','emp',no_invalidate=>false);
select sql_id, sql_text, parse_calls, loads, executions,invalidations
from v$sql
where sql_text like '%hr.emp%'
and sql_text not like '%v$sql%';

- 무효화를 주문했지만 오라클은 자체적으로 invalidation 되는건 성능상 좋지 않다고 판단하기 때문에 말을 듣지 않는다.
select * from hr.emp where employee_id = 100;
select sql_id, sql_text, parse_calls, loads, executions,invalidations
from v$sql
where sql_text like '%hr.emp%'
and sql_text not like '%v$sql%';

shared pool memory를 flush
alter system flush shared_pool;
SQL문 수행
select * from hr.emp where employee_id = 100;

select sql_id, sql_text, parse_calls, loads, executions,invalidations
from v$sql
where sql_text like '%hr.emp%'
and sql_text not like '%v$sql%';

select * from table(dbms_xplan.display_cursor('5g6ygund8wa94'));

alter table hr.emp add constraint emp_id_pk primary key(employee_id);
LCO를 다시 확인해보면 제약조건 추가로 인해 해당 실행계획이 무효화되어 invalidations가 1 증가하였다.

다시 똑같은 SQL문 수행 후 LCO를 확인하면 이전 LCO를 그대로 사용하지만, 실행계획이 무효화 되었었기 때문에 하드파싱이 발생되어 LOADS는 1 증가 되었고 PARSE_CALLS와 EXECUTIONS는 초기화 후 재사용 하기 때문에 1로 조회된다.
select * from hr.emp where employee_id = 100;
select sql_id, sql_text, parse_calls, loads, executions,invalidations
from v$sql
where sql_text like '%hr.emp%'
and sql_text not like '%v$sql%';

select * from table(dbms_xplan.display_cursor('5g6ygund8wa94'));

alter table hr.emp drop primary key;
select sql_id, sql_text, parse_calls, loads, executions,invalidations
from v$sql
where sql_text like '%hr.emp%'
and sql_text not like '%v$sql%';

select * from hr.emp where employee_id = 100;
select sql_id, sql_text, parse_calls, loads, executions,invalidations
from v$sql
where sql_text like '%hr.emp%'
and sql_text not like '%v$sql%';

select * from table(dbms_xplan.display_cursor('5g6ygund8wa94'));

create unique index hr.emp_idx on hr.emp(employee_id);
select sql_id, sql_text, parse_calls, loads, executions,invalidations
from v$sql
where sql_text like '%hr.emp%'
and sql_text not like '%v$sql%';

alter table hr.emp add constraint emp_id_pk primary key(employee_id) using index hr.emp_idx;
- primary key 제약조건을 설정하려고 하면 자동으로 unique index가 걸리는데 index의 이름은 제약조건의 이름으로 되게 자동으로 설정된다. 하지만 현재 이미 인덱스가 생성되어있기 때문에 using index절을 사용해야한다.
select sql_id, sql_text, parse_calls, loads, executions,invalidations
from v$sql
where sql_text like '%hr.emp%'
and sql_text not like '%v$sql%';

select * from hr.emp where employee_id = 100;
select sql_id, sql_text, parse_calls, loads, executions,invalidations
from v$sql
where sql_text like '%hr.emp%'
and sql_text not like '%v$sql%';

테이블 컬럼 확인
desc hr.emp
테이블 컬럼의 구조 변경
alter table hr.emp modify last_name varchar2(30);
select sql_id, sql_text, parse_calls, loads, executions,invalidations
from v$sql
where sql_text like '%hr.emp%'
and sql_text not like '%v$sql%';

select * from hr.emp where employee_id = 100;
select sql_id, sql_text, parse_calls, loads, executions,invalidations
from v$sql
where sql_text like '%hr.emp%'
and sql_text not like '%v$sql%';

library cache lock은 LCO(Library Cache Object)를 접근하거나 변경하는 경우 handle에 대해 획득하는 lock이다.
여러 세션에서 동시에 동일한 LCO를 변경하는 것을 방지하기 위해서 사용한다.
Library Cache Lock을 획득하지 못해 대기하는 경우 Library Cache Lock wait event 발생한다.
SQL문 hard parsing : library cache lock을 exclusive mode로 획득해야한다.
SQL문 execute 단계 : library cache lock을 shared mode로 획득해야한다.
alter문(테이블 구조가 변경) : library cache exclusive mode 획득해야한다.
create or replace procedure(function,package) : library cache exclusive mode 획득해야한다.
execute dbms_application_info.set_client_info('sess_1')
begin
for i in 1..10000 loop
execute immediate 'create or replace procedure hr.p1 is begin null; end;';
end loop;
end;
/
execute dbms_application_info.set_client_info('sess_2')
begin
for i in 1..10000 loop
execute immediate 'create or replace procedure hr.p1 is begin null; end;';
end loop ;
end;
/
select client_info, sid from v$session where client_info in ('sess_1','sess_2');

- 사라진 wait event는 조회되지 않는다.
select sid, event, wait_class, wait_time, seconds_in_wait, state
from v$session_wait
where sid in (274,294);

wait event : 작업을 수행하지 못하고 대기하는 상태v$session_wait : 세션이 현재 대기하고 있는 이벤트 정보, 누적정보가 아닌 실시간 정보이므로 반복적으로 조회해야 의미 있는 정보를 얻을 수 있다.- wait event에 대해 누적으로 조회
select sid, event, total_waits, time_waited
from v$session_event
where sid in (274,294);

v$session_event : 세션별 대기 이벤트의 누적 정보