리두(Redo)에서의 대기이벤트들

latch: redo writing, latch: redo allocation, latch: redo copy -> 리두 레코드를 리두 버퍼로 복사하는 과정 보호 위해 사용되는 래치들
1. redo writing 래치 : 리두 버퍼내의 공간 확보 위해 -> LGWR에게 쓰기 요청을 하려는 프로세스 - redo writing 래치 Willing-to-wait 모드로 획득해야함 - 경합시 latch: redo writing 대기 이벤트
이 래치는 전체 인스턴스에 하나만 존재한다 - LGWR 쓰기 작업이 동시에 수행 될 수는 없기에
2. redo copy 래치 : PGA내의 체인지 벡터를 리두 버퍼로 복사하려는 프로세스 - 작업 과정 내내 redo copy 래치 No-wait//Willing-to-wait 모드(일반적으로 No-wait모드로 획득시도하는데, 마지막 래치까지 왔는데도 획득 못했다면, 마지막 래치에 대해서는 Willing-to-wait모드로 획득 시도한다)로 획득하고 있어야함 - 경합시 latch: redo copy 대기 이벤트
3. redo allocation 래치 : PGA내의 체인지 벡터를 리두 버퍼로 복사하기 위해 -> 리두 버퍼내에 공간을 확보해야한다 -> 이 때 redo allocation 래치 획득해야함 - 경합시 latch: redo allocation 대기 이벤트
9i부터는 복수개의 redo allocation 래치를 사용한다 -> _LOG_PARALLELISM 파라메터를 통해 redo strands의 개수가 조정된다. || 하나의 redo allocation 래치가 하나의 redo strand관리
10g 부터는 Dynamic Parallelism 기능 도입 -> _LOG_PARALLELISM_DYNAMIC= TRUE로 지정하면 -> 동적으로 redo strands의 개수를 조정한다 (공식화 된 내용은 아니라함) - 최대 redo strand의 개수는 _LOG_PARALLELISM_MAX값 + 18이다.
10g 부터 private redo strands 기능 도입 -> 이 기능 사용하면 - 리두 레코드가 Shared Pool내의 private strands 영역에 생성됨 - private strands 영역은 공유 안됨 -> 따라서 래치 획득 불필요 -> LGWR은 PGA신경 쓸 것 없이, private strands영역에서 바로 내려 씀 -> _LOG_PRIVATE_PARALLELISM=TRUE로 하여 설정 가능 : 이 기능을 통하여 리두 관련 래치 경합을 완전히 피할 수 있겠으나 - 아직 logminer, logical standby, streams등과 호환이 되지 않는다고 한다.
불필요하게 리두 데이터가 많이 생성된다면 nologging 기능을 활용하는 방안도 있다 -> 복구 관련 문제 고려하도록


log file sync
커밋 또는 롤백시 -> LGWR: 리두 버퍼에서 가장 최근에 기록이 이루어진 시점부터 커밋 지점까지 리두 레코드를 리두로그파일에 기록 -> sync write라 부른다 -> redo synch writes 통계값을 통해 조회 가능
이때 서버 프로세스는 LGWR이 기록 마칠때까지 log file sync 이벤트 대기함 -> 오라클에서 가장 보편적인 대기 이벤트
log file sync 대기 이벤트 잦을때 의심 포인트
1. 커밋 회수가 지나치게 많지 않은가?
2. I/O 시스템이 느리지 않은가?
3. 리두 데이터가 불필요하게 생성되지는 않는가?
4. 리두 버퍼가 지나치게 크지 않은가?

커밋 회수와 log file sync
커밋 마다 log file sync가 한번 발생하기 마련 -> 여러 세션에서 동시에 커밋 날리면, 광범위하게 대기 이벤트 발생할 수 있다.
비슷한 순간에 수행된 커밋은 오라클이 알아서 모아서 커밋한다 = 그룹 커밋 -> 그렇다해도 기왕이면 트랜잭션 단위를 잘 묶어서 커밋하도록 하자
NOCACHE 옵션의 시퀀스 - row cache lock 대기 증가 || log file sync 대기 이벤트의 원인이 되기도 한다 -> sequence.nextval을 호출하면 딕셔너리 테이블 정보 갱신하고 커밋하므로 - 시퀀스 사용할때도 조심하세요

I/O 시스템의 성능과 log file sync
로그 파일 있는 스토리지 I/O 성능이 낮다면 -> sync write 수행 시간이 늘어나므로 -> log file sync 대기시간이 증가할 수 있다 -> 서버 프로세스가 log file sync 대기하는 동안 LGWR은 log file parallel write 대기 이벤트.
구성상 문제가 없는데도 리두가 자꾸 막히면 I/O 문제인지 살펴보도록 하자 -> 리두는 가장 빠른 스토리지에 위치시키는 것이 일반적이다.

리두 데이터의 양과 log file sync
커밋시 기록해야할 데이터가 늘어나면 -> 기록하는데 시간이 들어가니 -> log file sync 대기 시간이 증가한다. -> 리두 데이터를 줄이도록하자
오라클에서 제공되는 리두 데이터의 최소화 방안
1. nologging 옵션을 사용하면 리두 데이터가 확~ 줄어들 것이다 -> direct load, create, alter 등의 작업들은 대부분 nologging 가능
2. SQLLoader 사용시 - Direct load option 사용한다.
3. 임시 작업때는 임시 테이블을 사용하도록한다 -> 이경우 언두에 대한 리두는 생성되지만, 데이터 리두는 생선 안된다 -> 리두 양을 절반으로
4. 인덱스 있는 테이블에 direct load시 -> 인덱스를 unusable상태로 -> 데이터 생성 -> 인덱스를 nologging모드로 재구성
5. LOB 데이터도 가능하다면 nologging 사용하도록 한다.

리두 버퍼의 크기와 log file sync
리두 버퍼의 크기가 큰 경우에도 log file sunc 대기가 증가한다 -> sync write시 기록해야 할 데이터 양이 많기 때문
리두 버퍼의 사이즈는 시스템에 따라 적정 크기가 달라지겠지만
-> log file sync 대기가 증가한다면, 버퍼 크기를 줄여주고 || log buffer space 대기가 증가한다면 리두 버퍼 크기를 늘리도록 한다.
_LOG_IO_SIZE 히든 파라미터 -> LGWR이 리두 버퍼 기록할때 최대 값의 임계치 지정 => log buffer space 대기를 줄이기 위해 - 리두 버퍼 크기 올리고 , log file sync 대기를 줄이기 위해 _LOG_IS_SIZE 값을 작게준다.


log file parallel write - LGWR프로세스에서만 발생
LGWR 리두 버퍼의 내용을 리두 로그 파일에 기록시 -> I/O 작업이 완료되기를 기다리는 동안 log file parallel write 이벤트를 대기 - db file parallel write대기와 비슷하다. -> 이 두 대기 이벤트는 I/O성능과 관련이 있다.
빨리 내려 쓰지 못해서 발성하는 것이니 -> 리두버퍼가 커서 내려 써야되는 양이 많다거나, I/O 성능이 낮아서 쓰는데 오래 걸린다거나 하는 두가지 문제 중의 하나일 것이다
-> 어떻게든 빨리 내려 쓸 수 있도록 어플리케이션에서 최대한의 노력을 해 보고서 -> 시스템 교체등을 생각해 보는 것이 일반적이면서 경제적인 방법이 될 것이다.
일반적 해결법
- 불필요한 커밋을 줄인다
- Nologging 옵션을 활용하여 리두 데이터의 양을 줄인다.
- 리두 로그 파일이 위치한 I/O 시스템의 성능을 높인다.
- 핫백업을 너무 자주 수행하지 않는다 + 트랜잭션 많을때 핫백업 하지 말라 -> 핫백업 중에는 리두 데이터가 로우 레벨이 아닌 블록 레벨로 생성된다.

log buffer space
리두 버퍼에 리두 레코드를 기록하려면 -> 리두 버퍼내에 필요한 공간을 확보해야함 -> redo allocation 래치를 획득한다 -> 이제 공간을 확보하려고 보니 여유 공간이 없다 -> 공간이 확보될때까지 기다린다 -> 이때 경우에 따라 두가지의 대기 이벤트
log file switch completion - 사용중인 리두로그 파일이 꽉 찬 상태라면 - 리두 스위치 진행 될 테고 -> 스위치가 끝날때 까지 해당 이벤트 대기
log buffer space - 그 외의 경우 -> 리두 쌓이는 양에 비해, 리두 버퍼의 양이 적다면 발생한다.
둘이 동시에 발생한다면, 버퍼도 작고 파일도 작고 그럴 수 있다.
log buffer space는 LGWR 프로세스가 서버 프로세스들의 프리 리두 버퍼 요구 속도를 못 따라가며 발생 -> LGWR의 성능을 개선시킴으로써 log buffer space 대기 시간을 줄일 수 있을 것이다. -> 기록하는 양을 줄이거나, 기록하는 속도를 올리거나
log file switch completion이 발생한다 -> 스위치 끝나기를 기다림 -> 스위치 끝나고 그간 대기하던 작업들이 동시에 진행 될 것임 -> 이때 리두 버퍼를 동시에 많이 요구하더라 -> 그렇다면 log file switch completion발생 직후에 log buffer space 대기 이벤트도 발생하게 될 것임.


log file switch completion, log file switch(checkpoint incomplete), log file switch (archiving needed), log file switch (private strand flush incomplete)
리두로그 파일이 꽉 찼을때 -> 로그 스위치 발생하면서 -> 로그 스위치 끝날때까지 log file switch completion 이벤트 대기한다.
스위치하다보면 한바퀴 돌아서 썼던 리두 파일을 다시 쓴다 -> 헌데 새로 덮어쓰게될 리두 로그 파일에 대해 아직 진행중인 작업이 있는 상태라면 ->
1. 체크포인트 작업이 끝나지 않은 것이라면 -> DBWR - 체크 포인트가 끝나기를 먼저 기다린다 -> log file switch(checkpoint incomplete)
2. 아카이브 작업이 끝나지 않은 것이라면 -> ARCH가 아카이빙 끝내기를 기다린다 -> log file switch (archiving needed)
3. private strands가 flush 마치지 못했다면 -> 10gR2부터 생긴 이벤트. private redo strands 기능 사용한다면 발생함. flush 끝날 때까지 대기 -> log file switch (private strand flush incomplete)
-> 리두 데이터의 양에 비해 리두 파일의 크기가 지나치게 작다면 발생하게 될 것이다. -> 리두 데이터 양을 줄여 주거나, 파일을 키운다.