alter system set log_buffer = ... scope=spfile;(static parameter)SELECT max(lebsz) FROM x$kccle;
PGA내의 change vector를 redo log buffer로 복사하려면 redo copy latch를 획득해야 한다.
CPU개수의 2배
redo copy latch를 획득하지 못하면 latch : redo copy wait event가 발생한다.
redo copy latch의 수 확인
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 = '_log_simultaneous_copies';

select name, gets from v$latch_children where name = 'redo copy';

latch : redo allocation wait event가 발생한다.shared read strands라는 개념으로 redo log buffer의 영역을 일정 개수로 분할해서 사용함으로써 분할된 영역에 각각으로 redo allocation latch가 생성되었다.private redo strands 기능을 사용함으로써 PGA영역에서 change vector를 생성하는 것이 아니라 shared pool에 private redo strands영역에 저장하며 이 영역에 저장된 redo entry는 redo log buffer를 거치지 않고 바로 redo log file에 저장된다._log_parallelism_dynamic : 사용하면 true_log_private_mul : shared pool에서 private redo strands에 사용하는 비율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 ('_log_parallelism_dynamic','_log_private_mul');

select count(*) from v$latch_children where name = 'redo allocation';

select * from v$sgastat where name='private strands';

redo log buffer의 프리공간을 확보하기 위해 LGWR에게 쓰기 요청을 하려면 redo writing latch를 획득해야 한다.
1개만 존재한다.
redo writing latch를 획득못하면 latch : redo writing wait event가 발생한다.
1개만 있는 독립적인 latch는 v$latch_parent 뷰로 확인해야 한다.
select name,gets from v$latch_parent where name = 'redo allocation';

- 현재 세션에 대한 해당 구간의 redo 통계 정보 확인
- redo entries : redo entry가 redo log buffer에 기록된 횟수
- redo size : redo size(byte)
- redo synch writes : commit, rollback에 의해 수행된 redo write 수
- redo writes : LGWR가 수행된 수(redo synch writes가 있어서 commit, rollback 제외)
- redo blocks written : redo log file에 write된 redo log block 수
- redo log space requests : redo log buffer에 redo entry들을 redo log file에 쓰려는데 redo log file이 꽉차서 log switch가 발생한 횟수
- redo log space wait time : redo log space requests에 소요된 시간(1/100초)
select n.name, sum(s.value)
from v$sesstat s, v$statname n
where n.name in ('redo entries', 'redo size', 'redo synch writes', 'redo writes', 'redo blocks written', 'redo log space requests', 'redo log space wait time')
and s.statistic# = n.statistic#
and s.sid = (select sid from v$session where username = 'HR')
group by n.name;

- hr session
create table hr.redo_test(id number, name char(100)); : create 문장으로 인해 redo entry 생성 insert into hr.redo_test(id, name) select object_id, object_name from user_objects; : DML 작업으로 인해 redo entry 생성- sys session

select blocks, bytes/1024/1024 size_mb
from dba_segments
where owner = 'HR' and segment_name = 'REDO_TEST';

- hr session
rollback;
- sys session

- hr session
drop table hr.redo_test purge; : drop으로 인해 redo entry 생성
- sys session

select n.name, sum(s.value)
from v$sesstat s, v$statname n
where n.name in ('redo entries', 'redo size', 'redo synch writes', 'redo writes', 'redo blocks written', 'redo log space requests', 'redo log space wait time')
and s.statistic# = n.statistic#
and s.sid = (select sid from v$session where username = 'HR')
group by n.name;

- hr session
create table hr.redo_test(id number, name char(100)); : create 문장으로 인해 redo entry 생성 insert into hr.redo_test(id, name) select object_id, object_name from user_objects; : DML 작업으로 인해 redo entry 생성
- hr session에서 exit했다가 재접속 후 진행
insert /*+ append */ into hr.redo_test(id, name) select object_id, object_name from user_objects; : hint를 사용한 DML 작업으로 인해 redo entry 생성(direct path write)
# redo size delta = 9320 - 676
select blocks, bytes/1024/1024 size_mb
from dba_segments
where owner = 'HR' and segment_name = 'REDO_TEST';

select t.used_ublk, t.used_urec
from v$transaction t, v$session s
where s.sid = (select sid from v$session where username = 'HR')
and s.taddr = t.addr;

- hr session
rollback;truncate table hr.redo_test;- sys session
select blocks, bytes/1024/1024 size_mb
from dba_segments
where owner = 'HR' and segment_name = 'REDO_TEST';

- sys session redo 통계정보 확인
select n.name, sum(s.value)
from v$sesstat s, v$statname n
where n.name in ('redo entries', 'redo size', 'redo synch writes', 'redo writes', 'redo blocks written', 'redo log space requests', 'redo log space wait time')
and s.statistic# = n.statistic#
and s.sid = (select sid from v$session where username = 'HR')
group by n.name;

select logging from dba_tables where owner = 'HR' and table_name = 'REDO_TEST';alter table hr.redo_test nologging;alter table hr.redo_test logging;
insert /*+ append */ into hr.redo_test(id, name) select object_id, object_name from user_objects;

# redo size delta : 6608 - 676
=> redo 발생량을 줄이기위해 direct path를 사용할거면 해당 테이블을 nologging으로 설정해 최소화하면 좋음
- 오라클 SGA를 거치지 않고 데이터 파일에 직접 쓰기 작업 수행
- DBWR에 의해 쓰기 작업이 이뤄지는 것이 아니라 서버 프로세스에 의해 직접 쓰기 작업이 수행됨
- HWM(High Water Mark)이후에 블럭을 추가(append방식)
- 테이블의 nologging 옵션이 설정된 경우 redo 발생량을 줄일 수 있음
- 테이블의 TM LOCK을 exclusive하게 획득하기 때문에 다른 세션에서 DML이 허용되지 않음(따라서 밤에 주로 수행)
- 테이블 생성
create table hr.emp as select * from hr.employees;
- 새로운 redo 통계정보 확인
redo synch writes : commit, rollback에 수행된 redo write 수user commits : commit 수user rollbacks : rollback 수select n.name, sum(s.value)
from v$sesstat s, v$statname n
where n.name in ('redo synch writes', 'user commits', 'user rollbacks')
and s.statistic# = n.statistic#
and s.sid = (select sid from v$session where username = 'HR')
group by n.name;

- log file sync 이벤트에 대한 대기 정보를 조회
select event, total_waits, time_waited
from v$session_event
where sid = (select sid from v$session where username = 'HR')
and event = 'log file sync';

- hr session
update hr.emp set salary = salary * 1.1 where employee_id = 100;
commit;
- sys session

- hr session
update hr.emp set salary = salary * 1.1 where employee_id = 200;
rollback;
- sys session

- hr에서 새로 접속한 상태에서 초기 상태 확인 sys session
select n.name, sum(s.value)
from v$sesstat s, v$statname n
where n.name in ('redo synch writes', 'user commits', 'user rollbacks')
and s.statistic# = n.statistic#
and s.sid = (select sid from v$session where username = 'HR')
group by n.name;
select event, total_waits, time_waited
from v$session_event
where sid = (select sid from v$session where username = 'HR')
and event = 'log file sync';

- hr session
/*
커밋이 반복문 안에 있으면 돌아갈때마다 commit되는데
이는 성능에 좋지않으므로 오라클이 알아서 group commit을 진행
*/
declare
type numlist is table of number;
v_num numlist := numlist(100, 101, 200);
begin
for i in v_num.first..v_num.last loop
update hr.emp
set salary = salary * 1.1
where employee_id = v_num(i);
commit;
end loop;
end;
/
- sys session
redo synch writes : GROUP COMMIT으로 LGWR 작동횟수user commits : COMMIT문 횟수
PL/SQL 반복문 안에 있는 COMMIT문은 내부적으로 GROUP COMMIT으로 수행됨
즉 COMMIT이 3번 수행했지만 GROUP COMMIT의 개념으로 1번만 수행함 -> LGWR도 한번만 수행
log file switch completion이라는 이벤트 발생하며 대기initrans : Block header에 있는 transaction layer에 transaction slot의 수, 미리 생성한 transaction slot 수, 만약에 initrans 값이 5로 되어 있다면 미리 5개가 생성된다.(1개당 23byte)maxtrans : 데이터가 저장되어 있는 공간에 free 공간이 있으면 데이터저장공간에 transaction slot을 생성할 수 있는 최대수, 10g 부터는 고정되는 값으로 변경 255개pctfree : 처음 이 블록에 데이터가 저장될때 pctfree값을 제외시키고 입력한다.enq : TX - allocate ITL entry- 파라미터를 설정하여 테이블 생성
create table hr.itl_table(id number, l_name varchar2(1000), f_name varchar2(1000)) initrans 1 maxtrans 2 pctfree 0;

select ini_trans, max_trans, pct_free from dba_tables where owner = 'HR' and table_name = 'ITL_TABLE';

- 1000byte로 컬럼의 데이터값을 꽉 채워서 입력하였다.
insert into hr.itl_table(id,l_name,f_name)
select level, rpad('x',1000,'x'), rpad('z',1000,'z')
from dual
connect by level <= 10;
commit
- 통계정보 확인
select blocks, avg_row_len, ini_trans, max_trans, pct_free from dba_tables where owner='HR' and table_name='ITL_TABLE';

- 통계수집
execute dbms_stats.gather_table_stats('hr','itl_table')
- 통계수집 확인
select blocks, avg_row_len, ini_trans, max_trans, pct_free from dba_tables where owner='HR' and table_name='ITL_TABLE';

- 같은 block 안에 들어있는 row수 확인
select id, rowid, dbms_rowid.rowid_block_number(rowid) block_no
from hr.itl_table
order by 3;

<<session 1>>
update hr.itl_table
set l_name = rpad('y',1000,'y'), f_name = rpad('a',1000,'a')
where id = 1;

<<session 2>>
update hr.itl_table
set l_name = rpad('y',1000,'y'), f_name = rpad('a',1000,'a')
where id = 2;

<<session 3>>
update hr.itl_table
set l_name = rpad('y',1000,'y'), f_name = rpad('a',1000,'a')
where id = 3;

<<sys session>>
- enq : TX - allocate ITL entry wait event 확인
select sid, serial#, username, blocking_session, event, sql_id, prev_sql_id
from v$session
where event like '%TX%';

- prev_sql_id를 이용해서 lock이 걸려있는 쿼리문 확인
select sql_text from v$sql where sql_id = '8nxm7xrrj1yfj'

- lock을 일으키고 있는 prev_sql_id 값 확인
select sid, serial#, username, sql_id, prev_sql_id
from v\$session
where sid in (select blocking_session from v$session);

- 어떤 문장이 lock을 발생하고 있는지 확인
select sql_text from v$sql where sql_id = '3r949qb90g5pn'

- ITL 부족에 의한 경합이 발생한 정보 확인
select * from v$segment_statistics where owner='HR' and statistic_name='ITL waits';

- 해결방법
- block parameter 확인
select blocks, avg_row_len, ini_trans, max_trans, pct_free from dba_tables where owner='HR' and table_name='ITL_TABLE';

- initrans, pctfree 값 수정
alter table hr.itl_table initrans 2 pctfree 10;
- 수정된 값 확인
select blocks, avg_row_len, ini_trans, max_trans, pct_free from dba_tables where owner='HR' and table_name='ITL_TABLE';

- 재배치 시작
alter index 인덱스이름 rebuild online;alter table hr.itl_table move;
- 통계수집
execute dbms_stats.gather_table_stats('hr','itl_table')
- pct free 값 때문에 기존의 block 보다 더 많은 block를 사용하고 있다.
select blocks, avg_row_len, ini_trans, max_trans, pct_free from dba_tables where owner='HR' and table_name='ITL_TABLE';

- 같은 block 안에 들어있는 row수 확인
select id, rowid, dbms_rowid.rowid_block_number(rowid) block_no
from hr.itl_table
order by 3;

- 결과적으로 늘어난 ini trans 값과 pct free 공간으로 enq: TX - allocate ITL entry 이벤트는 발생되지 않는다.