BCHR = (buffer cache 곧바로 찾아 읽은 블록수 / 총읽은 블록수) * 100
= ((logical reads - physical reads)/logical reads) * 100
= (1- (physical reads / logical reads)) * 100
= (1 - (physical reads / (db block gets + consistent gets))) * 100
set autotrace on explainselect * from hr.emp where employee_id = 100;

set autotrace on statisticsselect * from hr.emp where employee_id = 100;

set autotrace traceonlyselect * from hr.emp where employee_id = 100;

set autotrace traceonly explainselect * from hr.emp where employee_id = 100;

set autotrace off
<<sys session>>
select s.prev_sql_id, s.prev_child_number, v.sql_text
from v$session s, v$sql v
where s.prev_sql_id = v.sql_id
and s.prev_child_number = v.child_number
and s.username = 'HR';
<<hr session>>
select * from hr.emp where employee_id = 100;
<<sys session>>
select s.prev_sql_id, s.prev_child_number, v.sql_text
from v$session s, v$sql v
where s.prev_sql_id = v.sql_id
and s.prev_child_number = v.child_number
and s.username = 'HR';

- v$sql_plan으로 보면 실행계획 보기가 까다롭다.
select * from v$sql_plan where sql_id = '5g6ygund8wa94';
- 패키지를 이용해 v$sql_plan의 내용을 보기 편하게 보여줌
select * from table(dbms_xplan.display_cursor('5g6ygund8wa94',0,'typical'));

- 바로 직전에 수행한 sql쿼리문의 대한 실행계획 확인
select * from hr.emp where employee_id = 110;
select * from table(dbms_xplan.display_cursor);

<<hr session>>
select * from hr.emp where employee_id = 110;
select * from table(dbms_xplan.display_cursor);

<<sys session>>
grant select on v_$session to hr;grant select on v_$sql to hr;grant select on v_$sql_plan to hr;grant select on v_$sql_plan_statistics to hr;grant select on v_$sql_plan_statistics_all to hr;<<hr session>>
select * from hr.emp where employee_id = 110;
select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));

- warning 에서 나온 hint를 사용해서 다시 조회해본다
select /*+ gather_plan_statistics */ * from hr.emp where employee_id = 110;
select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));

- 20번 부서인 사원은 총 2명이다.
root, branch, leaf block은 크기가 작아 한 블록안에 다 들어있다.
2개의 row를 access 하기 위해 원래는 leaf block은 3번을 i/o를 해야하지만 내부적으로 buffer pinning이 돌아가기 때문에 2번 이후부터는 latch를 잡지 않고 바로 해당 hash value의 값으로 조회가 가능해져 i/o는 2번으로 멈췄다.
전체 buffer는 2번의 leaf block i/0 + data block의 2번 i/o를 하였기 때문에 4번이다.
select /*+ gather_plan_statistics */ * from hr.employees where department_id = 20;
select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));

select /*+ gather_plan_statistics index(e EMP_DEPARTMENT_IX) */ * from hr.employees e where department_id = 50;
select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));

Id : 각 Operation번호
Operation : 실행되는 JOB
Name : Operation이 수행되는 테이블, 인덱스
Starts : 각 Operation을 반복 수행한 건수
E-Rows : 각 Operation을 수행했을때 return 건수(예상치)
A-Rows : 각 Operation을 수행했을때 return 건수(실제)
A-Time : 실제 실행시간 누적치
Buffers : 각 Operation의 logical block의 수 (논리적 블록 수, 전체 읽은 블록 수)
Reads : 각 Operation의 physical block의 수 (디스크에서 읽은 블록 수)
Write : 각 Operation의 disk에 write한 block의 수
- hr session
select /*+ gather_plan_statistics */ * from hr.emp where employee_id = 100;select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));
update /*+ gather_plan_statistics */ hr.emp set salary = salary * 1.1 where employee_id = 100;select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));
rollback;delete /*+ gather_plan_statistics */ from hr.emp where employee_id = 100;select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));
rollback;show parameter user_dump_dest : 예전에는 이 위치에 생성됐으나 지금은 사용하지않음
select name, value from v$diag_info; : 현재는 이 쿼리로 위치를 확인하고 사용
cd /u01/app/oracle/diag/rdbms/ora19c/ORA19C/trace, lsalter session set tracefile_identifier = 'test';alter session set sql_trace = true;select * from hr.employees where employee_id = 100;alter session set sql_trace = false;ls *test*
tkprof ORA19C_ora_10679_test.trc ex01.txtSQL ID: 2sgjc8u8ha0m4 Plan Hash: 1833546154
select *
from
hr.employees where employee_id = 100
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 2 0.00 0.02 8 2 0 1
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 4 0.00 0.02 8 2 0 1
Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: SYS
Number of plan statistics captured: 1
Rows (1st) Rows (avg) Rows (max) Row Source Operation
---------- ---------- ---------- ---------------------------------------------------
1 1 1 TABLE ACCESS BY INDEX ROWID EMPLOYEES (cr=2 pr=8 pw=0 time=25978 us starts=1 cost=1 size=69 card=1)
1 1 1 INDEX UNIQUE SCAN EMP_EMP_ID_PK (cr=1 pr=8 pw=0 time=25969 us starts=1 cost=0 size=0 card=1)(object id 72979)
# SELECT : Fetch 라인에서 disk, query 본다
# DML : Excute 라인에서 disk, current 본다
-Parse : SQL문을 파싱하고 실행계획을 생성하는데 대한 통계 정보
-Execute : DML문에 대한 통계 정보
-Fetch : SELECT문에 대한 통계 정보
- count : 실행횟수
- cpu : 처리에 소요되는 시간(초)
- elapsed : 처리에 소요되는 총 경과시간(초)
- disk : 물리적 블록 읽은 수
- query : 일관성 있는 (consistent) 읽기를 위한 논리적 블록 읽은 수(SELECT)
- current : 현재 모드에서 논리적 블록 읽은 수(DML)
- rows : 처리한 행의 수
- cr : consistent read, 논리적 블록 읽은 수
- pr : physical read, 물리적 블록 읽은 수
- pw : physical write, write 블록의 수
- time : 수행단계에서 소요된 시간(microsecond)
trace file 검색 이름 설정
alter session set tracefile_identifier = 'hr2';
Oracle 데이터베이스에서 SQL 성능 분석을 위해 10046 이벤트를 사용해 추적(trace)을 활성화하는 명령어
alter session set events '10046 trace name context forever, level 8';
sql 쿼리문 수행
select * from hr.employees where department_id = 20;
추적 종료
alter session set events '10046 trace name context off';
db file sequential read 이벤트는 single block i/o를 physical i/o로 하게 될때 발생되는 이벤트 이다.

db file scattered read 이벤트가 발생하는데 가끔 db file sequential read 이벤트가 발생할 때도 있다. 이는 physical i/o를 multi block i/o로 진행할때 어느 블록 까지 i/o를 하는지는 HWM를 기준으로 한다. 그 HWM는 segment의 header블록이 가지고 있다. 그 header 블록을 buffer에 올릴때는 single block i/o가 발생되기 때문에 db file sequential read가 발생한다.- 대용량 데이터 입력
create table hr.ind_random as select * from all_objects order by dbms_random.value;
alter system flush buffer_cache;
alter session set tracefile_identifier = 'hr4';
alter session set events '10046 trace name context forever, level 8';
select count(*) from hr.ind_random where owner='SYS';
alter session set events '10046 trace name context off';
SQL ID: 4whh8ak6wd1jc Plan Hash: 3056395443
select count(*)
from
hr.ind_random where owner='SYS'
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 0 1 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 2 0.00 0.00 1396 1397 0 1
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 4 0.00 0.00 1396 1397 1 1
Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: SYS
Number of plan statistics captured: 1
Rows (1st) Rows (avg) Rows (max) Row Source Operation
---------- ---------- ---------- ---------------------------------------------------
1 1 1 SORT AGGREGATE (cr=1397 pr=1396 pw=0 time=2427 us starts=1)
52254 52254 52254 TABLE ACCESS FULL IND_RANDOM (cr=1397 pr=1396 pw=0 time=4648 us starts=1 cost=266 size=12355 card=2471)
Elapsed times include waiting on following events:
Event waited on Times Max. Wait Total Waited
---------------------------------------- Waited ---------- ------------
Disk file operations I/O 1 0.00 0.00
SQL*Net message to client 2 0.00 0.00
db file sequential read 1 0.00 0.00
direct path read 50 0.00 0.00
PGA memory operation 1 0.00 0.00
SQL*Net message from client 1 0.00 0.00
- 이벤트를 주어 full table scan을 의도적으로 발생
alter system flush buffer_cache;
alter session set events '10949 trace name context forever, level 1';
alter session set tracefile_identifier = 'hr5';
alter session set events '10046 trace name context forever, level 8';
select count(*) from hr.ind_random where owner='SYS';
alter session set events '10046 trace name context off';
alter session set events '10949 trace name context off';
SQL ID: 4whh8ak6wd1jc Plan Hash: 3056395443
select count(*)
from
hr.ind_random where owner='SYS'
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 2 0.00 0.01 1396 1399 0 1
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 4 0.00 0.01 1396 1399 0 1
Misses in library cache during parse: 0
Optimizer mode: ALL_ROWS
Parsing user id: SYS
Number of plan statistics captured: 1
Rows (1st) Rows (avg) Rows (max) Row Source Operation
---------- ---------- ---------- ---------------------------------------------------
1 1 1 SORT AGGREGATE (cr=1399 pr=1396 pw=0 time=10289 us starts=1)
52254 52254 52254 TABLE ACCESS FULL IND_RANDOM (cr=1399 pr=1396 pw=0 time=2997 us starts=1 cost=266 size=12355 card=2471)
Elapsed times include waiting on following events:
Event waited on Times Max. Wait Total Waited
---------------------------------------- Waited ---------- ------------
Disk file operations I/O 1 0.00 0.00
SQL*Net message to client 2 0.00 0.00
db file sequential read 1 0.00 0.00
db file scattered read 47 0.00 0.00
SQL*Net message from client 2 0.00 0.00
테이블이나 인덱스에 대한 full table scan 발생할 경우 multi block i/o가 발생한다.
이때 데이터베이스 버퍼 캐시 영역의 부담을 줄 수 있다.
데이터 파일의 블록을 메모리로 읽어 오려면 cache buffers lru chain latch 획득한 후 프리 공간을 스캔하고 프리공간에 올리는 작업을 수행한다.
_small_table_threshold 설정되어 있는 블록의 수 보다 많은 블록을 가지고 있는 테이블을 full table scan이 발생하면 direct path read 방식으로 디스크에 블록들을 PGA영역으로 바로 읽어 오는 기능이 11g 부터 지원이 된다.
원래는 direct path read 방식은 병렬 처리시에 발생하는 기능이지만, 11g부터 serial direct read 방식으로 구현이 된다.
select a.ksppinm as parameter,b.ksppstvl as session_value, c.ksppstvl as instance_value
from x$ksppi a, x$ksppcv b, x$ksppsv c
where a.indx = b.indx
and a.indx = c.indx
and a.ksppinm in ('_small_table_threshold','_serial_direct_read');

alter session set events '10949 trace name context forever, level 1';select extent_id, block_id, bytes, blocks
from dba_extents
where owner='HR'
and segment_name='IND_RANDOM'
EXTENT_ID BLOCK_ID BYTES BLOCKS
---------- ---------- ---------- ----------
0 9928 65536 8
1 9936 65536 8
2 9944 65536 8
3 9952 65536 8
4 9960 65536 8
5 9968 65536 8
6 9976 65536 8
7 10112 65536 8
8 10120 65536 8
9 10128 65536 8
10 10136 65536 8
11 10144 65536 8
12 10152 65536 8
13 10160 65536 8
14 10168 65536 8
15 10176 65536 8
16 10240 1048576 128
17 10368 1048576 128
18 10496 1048576 128
19 10624 1048576 128
20 10752 1048576 128
21 10880 1048576 128
22 11008 1048576 128
23 11136 1048576 128
24 11264 1048576 128
25 11392 1048576 128
26 11520 1048576 128
- index를 설정후 건수 세기
select count(*) from hr.ind_random where owner='SYS';
COUNT(*)
----------
52254
SYS@ORA19C> select count(*) from hr.ind_random where owner='HR';
COUNT(*)
----------
60
create index hr.ind_random_ix on hr.ind_random(owner);
alter system flush buffer_cache;
alter session set tracefile_identifier = 'hr6';
alter session set events '10046 trace name context forever, level 8';
select count(*) from hr.ind_random where owner='SYS';
alter session set events '10046 trace name context off';
select count(*)
from
hr.ind_random where owner='SYS'
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 2 0.00 0.00 111 111 0 1
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 4 0.00 0.00 111 111 0 1
Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: SYS
Number of plan statistics captured: 1
Rows (1st) Rows (avg) Rows (max) Row Source Operation
---------- ---------- ---------- ---------------------------------------------------
1 1 1 SORT AGGREGATE (cr=111 pr=111 pw=0 time=8113 us starts=1)
52254 52254 52254 INDEX RANGE SCAN IND_RANDOM_IX (cr=111 pr=111 pw=0 time=7454 us starts=1 cost=6 size=12355 card=2471)(object id 76300)
Elapsed times include waiting on following events:
Event waited on Times Max. Wait Total Waited
---------------------------------------- Waited ---------- ------------
Disk file operations I/O 1 0.00 0.00
SQL*Net message to client 2 0.00 0.00
db file sequential read 111 0.00 0.00
SQL*Net message from client 2 1.55 1.55
- sys유저로 조건을 건 뒤 전체 데이터 조회
select /*+ gather_plan_statistics */ * from hr.ind_random where owner='SYS';
select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));

- hint를 주어 full table scan을 유발했다. i/o 수가 많이 줄었다.
select /*+ gather_plan_statistics full(i) */ * from hr.ind_random i where owner='SYS';
select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));

- 해당 실행계획을 보게되면 52254개의 owner가 sys인 값을 index range scan했기 때문에 buffer pinning이 실행되어 112개의 i/o로 줄었지만 object_name 이 all_objects 인 값이 1개 밖에 없는데 해당 값을 찾고자 1385개의 데이터 buffer를 i/o 해야하기때문에 성능이 좋지 않다.
select /*+ gather_plan_statistics */ * from hr.ind_random where owner='SYS' and object_name = 'ALL_OBJECTS';
select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));

- 해당 문제를 해결하기 위해서는 owner 와 object_name 컬럼을 조합인덱스로 설정해야 한다.
create index hr.ind_random_idx on hr.ind_random(owner,object_name);
select /*+ gather_plan_statistics */ * from hr.ind_random where owner='SYS' and object_name = 'ALL_OBJECTS';
select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));

- index의 leaf block 까지 가기 전의 root, branch block의 i/o 수 확인
select ix.index_name, ix.uniqueness, ic.column_name, ix.blevel
from dba_indexes ix, dba_ind_columns ic
where ix.index_name = ic.index_name
and ix.table_name = 'IND_RANDOM'
and ix.owner='HR';
