Data Base/SQL 튜닝

Redo 기능, logging mode & nologging mode

잇꼬 2024. 2. 7. 19:18
728x90
반응형
SMALL

■ Redo 기능

- Database '복구'를 목적으로 설계

- Database에 적용된 모든 변경 사항에 대한 이력 저장

- DML/DDL/Recursive SQL(select .. from .. for update : lock)에 의해 변경된 모든 Data 이력 (nologging 제외)

- DDL Text 저장 (DML Text 제외)

 

■ LGWR에 의한 Redo 기록

- Redo Buffer 내용을 Redo Log File 에 기록하는 시점

- 매 3초 마다

- Log Buffer의 1/3 또는 1MB 가 저장될 때

- User Process가 Commit 또는 Rollback으로 Transaction을 종료할 때 (Log Force at Commit)

- DBWR Process(발생하기 전)에 의해 신호를 받을 때 (write ahead logging)

 

■ Log Force at Commit

- 모든 log write 끝났을 때

- Transaction과 관련된 모든 Redo Record를 Log File에 저장 후 Commit 완료

 

■ Write Ahead Log

- 디스크로 내려가기 전에 / Data Buffer에 기록하기 전에 Log Buffer에 먼저 기록

- Data File에 기록하기 전에 Log File에 먼저 기록

 

※ Redo Allocation Latch 및 Shared/Private Redo Strands에 대한 Oracle 버전별 변화 정리

1) 8i 버전

  ▶ Redo Allocation Latch는 시스템 전체에 1개만 존재.
  Redo Buffer의 메모리 할당은 한 번에 하나의 프로세스만 가능

2) 9i 버전

  Shared Redo Strands 도입
     - Redo Buffer의 영역을 분할하여 여러 Strands로 나누어 사용.
     - 각 Strand는 별도의 Redo Allocation Latch를 사용하여 메모리 할당.
  _log_parallelism 파라미터 활용
     - redo strand의 개수를 지정하는데 사용.
     - CPU 수에 따라 적절한 값을 설정하여 경합 발생 가능성을 줄임.

3) 10g 버전

  동적인 Redo Strands 관리
     - Oracle이 Shared Redo Strands의 개수를 동적으로 관리.
     - _log_parallelism_dynamic 히든 파라미터를 TRUE로 설정하여 활성화.
  Private Redo Strands 도입
     - 각 세션마다 개별적인 Redo Strands를 사용하는 Private Redo Strands 도입.
     - 리두 데이터를 PGA 영역에서 Change Vector를 생성하는 대신 'Shared Pool'의 Private Strands 영역에 저장.
     - 저장된 로그 데이터는 Redo Buffer를 거치지 않고 Redo Log File에 직접 저장됨.
  _log_private_parallelism 파라미터
     - Private Redo Strands 기능을 활성화하려면 이 파라미터를 TRUE로 설정.

4) 10gR2 버전

  Private Redo Strands 공간 할당
     - Private Redo Strands를 위한 공간은 'LOG_BUFFER' 내에 생성.
     - _log_private_mul 파라미터에 지정된 비율만큼(LOG_BUFFER의 5%)을 Private Redo Strands 공간으로 사용.
  Zero Copy Redo
     - Latch Redo Copy 과정이 필요 없이 바로 Redo Log File에 저장되는 기능.
     - 이로써 Latch 경합을 최소화함.

 

▷ 요약

 

- 8i에서는 Redo Allocation Latch가 하나였고, 9i에서 Shared Redo Strands로 분할하여 경합을 감소시켰다.
- 10g에서는 동적인 Strand 관리 및 Private Redo Strands를 도입하여 개별 세션의 Redo Strands를 활성화했다.
- 10gR2에서는 Zero Copy Redo를 도입하여 Latch 경합을 최소화하고, Private Redo Strands의 공간을 LOG_BUFFER에서 할당함.

 

※  logging mode & nologging mode 

  logging mode nologging mode
의미 변경된 데이터를 DB redo log file에 기록하는 모드.
트랜잭션에서 수핸한 모든 데이터 변경 작업이 redo log에 기록되어 데이터베이스의 무결성과 복구 기능을 보장한다.
변경된 데이터를 redo log에 기록하지 않는 모드.
변경된 데이터가 redo log에 기록되지 않으므로 데이터베이스의 무결성은 유지되지만, 복구 기능은 로그 기록이 없어서 제한된다.
장점 변경된 데이터의 완전성과 데이터베이스 복구가 가능하다 redo log에 기록하지 않기 때문에 redo log file이 증가하지 않고, I/O 부하가 감소
단점 edo log 파일이 계속 증가할 수 있고, 변경 작업이 로깅되는 만큼 I/O 부하가 발생할 수 있다. 데이터베이스의 무결성을 유지하는 동시에 복구 기능이 제한되므로 주의해서 사용

 


 

#) 히든 파라미터 확인

SELECT    a.ksppinm  Parameter, b.ksppstvl  Value
FROM   x$ksppi a,   x$ksppcv b
WHERE   a.indx = b.indx
AND   a.ksppinm in ('_log_parallelism_dynamic','_log_private_mul');

 

#) redo log buffer latch

- latch : redo copy

의미) redo log buffer 에 있는 변경 사항을 디스크에 기록하기 위해 redo log를 복사하는 작업에 대기한다.

발생 원인) 리두 로그 버퍼의 내용을 리두 로그 파일에 영구적으로 기록하기 위해 디스크에 데이터를 복사하는 과정에서 여러 세션 간에 리두 로그 버퍼에 접근하는 경우 경합 조건이 발생.

- latch : redo allocation

의미) redo log buffer 에서 공간을 할당할 때 대기. 새로운 redo log 레코드를 buffer에 쓰기 위해 공간을 할당하는 작업에 대기한다.

발생 원인) 여러 세션에서 동시에 리두 로그 버퍼에 새로운 로그 레코드를 작성하려고 할 때, 리두 로그 버퍼의 할당에 대한 경합 조건이 발생.

- latch : redo writing 

→ 과하게 발생하면? 원인) free 공간 부족 log_parameter 확인  변경

=> redo buffer에 생성 => write 작업 => 속도 향상 

의미) redo log를 디스크에 기록하는 작업에서 대기한다.

발생 원인) 리두 로그 버퍼에 있는 변경 사항을 리두 로그 파일에 기록하기 위해 디스크에 쓰기 작업이 발생할 때 여러 세션이 동시에 접근하면 리두 로그 파일에 대한 경합 조건이 발생.

 

 


<sys session>

#) undo 확인 

select t.used_ublk, t.used_urec
from v$transaction t, v$session s
where s.sid = (select sid from v$mystat where rownum = 1)
and s.taddr = t.addr;

 

 

#) 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$mystat where rownum = 1)
group by n.name;

 

#) 테이블 생성

create table hr.redo_table(id number, name char(100));

 

#) 대량의 data 로드

insert into hr.redo_table(id, name) select object_id, object_name from dba_objects;

 

#) undo 확인 

select t.used_ublk, t.used_urec
from v$transaction t, v$session s
where s.sid = (select sid from v$mystat where rownum = 1)
and s.taddr = t.addr;

USED_UBLK ; undo 블록

USED_UREC ; undo 레코드 수

 

#) redo 모니터링 통계 정보

redo synch writes   2 => DDL 문장 수행

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$mystat where rownum = 1)
group by n.name;

 

#) rollback 후 redo 정보 확인

redo synch writes 3 => DDL 문장 + rollback 

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$mystat where rownum = 1)
group by n.name;

 

## 해석 ##

redo entries : redo entry가 redo log buffer에 기록된 횟수

redo size : redo size(byte)

redo log space requests : redo log buffer에 redo entry 들을 LGWR가 redo log file에 쓰려고 하는데 log file이 꽉차서 log switch가 발생한 횟수

redo log space wait time : redo log space requests에 소요된 시간(1/100 초)

redo synch writes : commit 또는 rollback 에 의해 수행된 redo write 횟수

redo blocks written : redo log file에 write된 redo log block 수 (redo log buffer 크기는 OS 블록에 맞춰서)

redo writes : LGWR 수행한 수

 

#) redo table 사이즈 확인

select blocks, bytes/1024/1024 mb
from dba_segments
where segment_name = 'REDO_TABLE';


 

<< new session >>

insert문 : /*+ append */ 사용 

-> 앞에 block이 비워져있다면 사용해도 무방

-> /*+ append */ 사용 : undo, redo 발생량 줄이는데 효과적, 복구 목적X

=> HWM 제일 뒤에있는 block 에 추가 / 장점) insert 속도 빠름 / 단점)공간 낭비 

 

#) 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$mystat where rownum = 1)
group by n.name;

 

#) 대량의 data 로드

=> /*+ append */ 힌트 사용

insert /*+ append */ into hr.redo_table(id, name) select object_id, object_name from dba_objects;

 

#) undo block 수

select t.used_ublk, t.used_urec
from v$transaction t, v$session s
where s.sid = (select sid from v$mystat where rownum = 1)
and s.taddr = t.addr;

 

#) redo 발생량 확인

insert문 실행

redo entries 1539 => 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$mystat where rownum = 1)
group by n.name;

 

#) redo table의 수

select blocks, bytes/1024/1024 mb
from dba_segments
where segment_name = 'REDO_TABLE';

 

#) rollback하고 나서 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$mystat where rownum = 1)
group by n.name;

 

#) truncate 이후 redo size 확인해보기

=> daliy 성 table이라면?

truncate table hr.redo_table;

select blocks, bytes/1024/1024 mb
from dba_segments
where segment_name = 'REDO_TABLE';

 


<< new 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$mystat where rownum = 1)
group by n.name;

 

#) nologging mode / logging mode인지 확인

select logging from dba_tables where table_name = 'REDO_TABLE';

 

#) nologging mode 로 변경

alter table hr.redo_table nologging;

 

#) nologging mode / logging mode인지 확인

select logging from dba_tables where table_name = 'REDO_TABLE';

 

#) redo 모니터링 확인

=> alter문 이후 redo 정보 확인

redo synch writes 1 => commit문 돌아감!

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$mystat where rownum = 1)
group by n.name;

 


 

<< new 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$mystat where rownum = 1)
group by n.name;

 

#) 대량의 data 로드

insert /*+ append */ into hr.redo_table(id, name) select object_id, object_name from dba_objects;

 

#) insert문 이후의 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$mystat where rownum = 1)
group by n.name;

 

#) undo 수 확인 

select t.used_ublk, t.used_urec
from v$transaction t, v$session s
where s.sid = (select sid from v$mystat where rownum = 1)
and s.taddr = t.addr;

 

#) redo table 확인 

select blocks, bytes/1024/1024 mb
from dba_segments
where segment_name = 'REDO_TABLE';

  

#) rollback 이후 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$mystat where rownum = 1)
group by n.name;

 

#) truncate 이후 size 확인

truncate table hr.redo_table;

select blocks, bytes/1024/1024 mb
from dba_segments
where segment_name = 'REDO_TABLE';

 

 

#) logging 모드 확인 후에 다시 nologging 모드로 변경해주기 

select logging from dba_tables where table_name = 'REDO_TABLE';

 

alter table hr.redo_table logging;

select logging from dba_tables where table_name = 'REDO_TABLE';

728x90
반응형
LIST