|
03 비관적 vs. 낙관적 동시성 제어
- 비관적 동시성 제어는 잘못 사용하면 동시성을 제어 받는다.
- 낙관적 동시성 제어는 Lock이 유지되는 시간이 짧아져 동시성을 높일수 있지만 별도의 처리절차가 있다.
(1) 비관적 동시성 제어
- 비관적 동시성 제어 (Pessimistic Concurrency Control) : 사용자들이 같은 데이터를 동시에 수정할 것이라고 가정한다.
=> Locking은 첫 번째 사용자가 트랜잭션을 완료하기 전까지 다른 사용자들이 그 데이터를 수정할 수 없게 만든다.
=> 사용자들이 같은 데이터를 동시에 수정하는 일은 비관적(Pessimistic) 이다.
- select 문에 for update 를 사용하면 데이터가 잘못 갱신되는 문제를 방지할 수 있지만, select 시점에 Lock(for update)을 거는
비관적 동시성 제어는 시스템 동시성을 심각하게 떨어 뜨릴 수 있다.
Sol) wait / nowait 옵션을 함께 사용하면 Lock을 얻기 위해 무한정 기다리지 않아도 된다.
=> 별도의 메시지를 출력하고 트랜잭션을 종료할 수 있다 -> 동시성을 증가시킬 수 있다.
(2) 낙관적 동시성 제어
- 낙관적 동시성 제어 (Optimistic Concurrency Control) : 사용자들이 같은 데이터를 동시에 수정하지 않을 것이라고 가정한다.
=> 데이터를 읽을 때는 Lock을 설정하지 않는다. But, 데이터를 수정하고자 하는 시점에 앞서 읽은 데이터가 다른사용자에
의해 변경되었느지를 반드시 검사해야 한다. : 귀찮은 처리 절차
- update 문을 수행하기 이전에 select 문에서 읽은 컬럼들이 매우 많다면 update 문에 조건절을 일일이 기술하는 것은 귀찮다.
Sol) update 문에 최종변경일시를 관리하는 컬럼을 두고 이를 조건절에 넣음으로써 해결할 수 있다.
- 낙관적 동시성 제어에서도 wait / nowait옵션을 사용한 select문을 두면 다른트랜잭션에 의해 설정된 Lock에 의한 동시성
저하를 예방할 수 있다.
- 위에 Sol) 에서 말한 최종변경일시컬럼(Timestamp) 를 두고 동시성 제어를 하려고 할때, 변경일시 컬럼까지 변경하는 규칙을
지키지 않는다면 Lost Update문제가 재발하게 된다.
=> 오라클 10g부터 제공되는 Pseudo 컬럼 ora_rowscn을 활용한다면 Timestamp를 오라클이 직접 관리해 준다.
=> 이 기능을 사용하려면 테이블을 생성할 때 ROWDEPENDENCIES 옵션을 사용해야 한다.
EX) CREATE TABLE TEST
ROWDEPENDENCIES
AS
SELECT * FROM TSET_1;
- ora_rowscn은 영구히 저장되는 값이지만 이를 시간정보로 변환하는 데에는 정해진 기한이 있다.
- SMON 프로세스는 내부적으로 SCN과 Timestamp 간 매핑 정보를 관리하며, 오라클은
이 매핑 정보(sys, smon_scn_time테이블) 를 이용해 scn_to_timestamp 함수를 구현했다. -> 이 매핑 정보 보관주기는 5일
- 하지만, ora_rowscn을사용할 때 두 트랜잭션이 동시에 update 문을 수행하게 된다면 버그(Bug 5270479)가 발생한다
-> Lost update
04 동시성 구현 사례
(1) 일련번호 채번 동시성 높이기 ※ 채번 : 고유번호를 할당받아 사용하다.
- Locking 을 최소화 하면서 채번 테이블로부터 일련번호를 채번하고자 할 때
- 일련번호를 채번하고자 할 때 가장 좋은 선택은 DBMS가 제공하는 Sequence 기능을 이용하는 것이다.
=> Sequence 기능을 사용할 수 없는 경우 사용되는 다른 방법 :
1. 데이터가 삽입되는 시점에 실시간으로 MAX 값을 취해 1만큼 증가시킨 값을 이용
-> 두 개의 트랜잭션이 동시에 같은 값을 읽었을 경우, insert하려는 순간 PK 제약에 위배되므로 동시성 제어 가능
2. MAX 값을 관리하는 별도의 채번 테이블에서 값을 가져오는 방식
-> 채번 후 다음 처리로 진행하기 전에 채번 테이블 값을 1만큼 증가시키는 갱신을 수행해야 한다.
=> 함수를 정의하는 트랜잭션(메인) 에서 커밋을 날릴경우 그 함수를 사용하는 트랜잭션(서브)이 같은 데이터에 변경을 가할 경우 문제가 생긴다.
=> 그렇다고 메인 트랜잭션에서 커밋을 날리지 않는다면 Lock이 걸리게 되고 메인 트랜잭션에만 묶여 있게 된다.
=> 이럴 경우 오라클에서는 'autonomous 트랜잭션' 기능을 제공한다.
※ autonomous 트랜잭션 : 메인 트랜잭션 (함수 정의) 에 영향을 주지 않고 서브 트랜잭션 (정의된 함수 사용)만
따로 커밋하는 기능
(2) 선분이력 정합성 유지
- 선분이력을 추가하고 갱신할 때 발생할 수 있는 동시성 이슈를 해결한 사례
- 선분이력모델은 데이터 정합성이 쉽게 깨질 수 있다는 단점이 있다.
※ 선분이력모델 : 이력의 시작시점만을 관리하는 것을 '점'이력이라' 모델이라 하고, 시작시점과 종료시점을 함께
관리하는 것을 '선분이력'모델이라 한다
선분이력 : 한 Entity에서 튜플(Tuple)이 가지고 있는 의미(관리 속성들이 의미하는 정보)가 일정 시점의 정보만을
나타내는 것이 아니라 일정기간(선분)이 유지되는 동안 해당 정보가 유효 하다는 의미이다.
즉, 현 Entity에서 관리하고자 하는 모든 정보는 해당 기간(선분)동안 유효 하다는 개념이다.
- 컬럼에 데이터가 없는경우 select for update로 Lock을 걸 수 없어 한개의 데이터의 동시에 변경을 가할수 있게된다.
=> 그렇게 되면 시작일시는 다르면서 종료일시가 같은 두 개의 이력레코드가 생기게 된다.
=> 이것을 막기 위해 상위 엔티티에 Lock을 걸면 완벽하게 동시성제어를 할 수 있다.
05 오라클 Lock
- 래치 : SGA에 공유돼 있는 갖가지 자료구조를 보호할 목적으로 사용하는 가벼운 Lock
- 버퍼 Lock : 버퍼 블록에 대한 액세스를 직렬화
- 라이버르러 캐시 Lock : 라이브러리 캐시 오브젝트에 대한 핸들을 보호
- 라이브러리 캐시 Pin : 라이브러리 캐시 오브젝트의 실제 내용이 담긴 힙을 보호
- DML 테이블 Lock : Enqueue Lock으로 구현함
- DML 로우 Lock : 로우 단위 Lock과 트랜잭션 Lock을 조합해서 구현함 (트랜잭션 Lock은 Enqueue Lock으로 구현)
(1) Enqueue Lock
- Enqueue : 공유 리소스에 대한 액세스를 관리하는 Lock 메커니즘
=> 보호되고 있는 공유 리소스 : 테이블 / 트랜잭션 / 테이블스페이스 / 시퀀스 / Temp 세그먼트...
- Enqueue Lock은 래치와 달리 순서가 보장되는 Queue 구조를 사용한다.
=> 대기자 Queue에 가장먼저 Lock요청을 등록한 세션이 가장먼저 Lock을 획득한다.
=> Lock을 획득하려면 Enqueue 리소스를 할당받아야 한다.
- Enqueue 리소스 : 소유자 / 대기자 목록을 관리할 수 있는 구조체
=> 고유 식별자가 부여되며 식별자는 <Type - ID1 - ID2>로 구성된다.
1. Type : TX / TM / TS 처럼 2개 문자열로 이루어 진다.
2. ID1 / ID2 : Lock 종류에 따라 다른 정보를 갖는다.
EX) TM Lock 식별자 ---- Type : TM / ID1 : 오브젝트 ID / ID2 : 0
TX Lock 식별자 ---- Type : TX / ID1 : Undo 세그먼트 번호 + 트랜잭션 슬롯번호 /
ID2 : 트랜잭션 슬롯 Sequence 번호
- 오라클은 Enqueue 리소스를 통합관리하는 리소스 테이블을 갖는다.
=> 리소스 테이블에서 관리되는 각 리소스를 찾을 때는 해싱 알고리즘을 사용한다.
- 해싱을 위한 해시 키로는 리소스 식별자가 사용된다.
=> 각 해시 버킷에는 연결 리스트로 연결된 해시 체인을 가지며, 여기에 리소스 구조체가 연결된다.
- Enqueue 방식으로 관리되는 리소스에 대해 Lock 획득
1. 리소스 테이블에서 해당 리소스 구조체를 찾는다.
2. 리소스 구조체가 없다면 새로운 리소스 구조체를 할당 받아 해시 체인 연결 리스트에 연결한다.
3. 리소스 구조체의 소유자 목록에 자신을 등록한다.
4. 호환되지 않는 모드로 먼저 Lock을 획득한(소유자 목록에 등록된) 세션이 있다면
Lock 요청을 대기자 목록에 등록하고 대기해야 한다.(작업을 포기할 수도 있다.)
=> 소유자가 Exclusive 모드: 한 순간에 하나의 세션만 Lock 획득
Shared 모드 : 여러 세션이 동시에 Lock 획득
=> Shared 모드와 Shared 모드는 서로 호환된다.
=> Shared 모드와 Exclusive 모드는 서로 호환되지 않는다.
=> Exclusive 모드와 Exclusive 모드는 서로 호환되지 않는다.
(2) TX Lock (트랜잭션 Lock)
- 변경 중인 레코드를 동시에 변경하려는 트랜잭션에 대해서는 액세스를 직렬화 해야한다.
=> 이럴 때 사용하는 Lock 메커니즘이 트랜잭션 Lock(TX Lock) 이다.
- TX Lock은 트랜잭션이 첫 번째 변경을 시작할 때 얻고, 커밋 또는 롤백할 때 해제한다.
- TX Lock도 Enqueue Lock으로 구현되었다.
- TX Lock을 위한 Enqueue 리소스 구조체의 식별자
1. TYPE : TX
2. ID1 : Undo 세그먼트 + 트랜잭션 슬롯번호
3. ID2 : 트랜잭션 슬롯 Sequence 번호
- 이 식별자를 갖는 리소스 구조체를 Enqueue 리소스 테이블 해시 체인에 연결하고, 소유자 목록에 트랜잭션을 등록
-> Lock 획득
- TX Lock 메커니즘
1. TX1 트랜잭션은 Undo 세그먼트에서 트랜잭션 슬롯을 할당받고, Enqueue리소스를 통해 TX Lock을 설정한다.
이 과정에서 r1 ~ r5까지 변경하고 커밋하지 않는다.
2. TX2도 트랜잭션 테이블에서 하나의 슬롯을 할당 받고, Enqueue 리소스를 통해 TX Lock 을 설정한 후 r6 레코드를
변경한다.
3. TX2가 r3 레코드를 액세스 할때 TX1이 Lock 을 걸고 있으므로 TX1의 상태를 확인한다.
4. TX1이 아직 커밋하지 않았으므로 TX2는 TX1이 Lock 을 설정한 Enqueue 리소스 구조체 대기자 목록에 자신을
등록하고, 대기상태로 들어간다.
5. TX2는 대기하면서 3초마다 TX1이 설정한 TX Lock 상태를 확인한다. -> 교착상태 발생 여부를 확인하기 위함
6. TX1이 커밋 또는 롤백하면, 가장 우선순위가 높은 TX2 트랜잭션을 깨워 트랜잭션을 재개하도록 한다.
- id1 / id2 를 이용해 TX Lock을 소유한 트랜잭션의 Undo 세그먼트와 트랜잭션 슬롯번호 / 시퀀스 번호까지 식별할 수 있다.
- v$lock 뷰를 이용해 TX Lock 경합 상황을 모니터링 할 수 있다.
- v$session_wait / 이벤트 트레이스를 통해 원인을 파악할 수 있다. -> 대기 이벤트 발생 현황 관찰
(3) TX Lock -> 무결성 제약 위배 가능성 또는 비트맵 인덱스 엔트리 갱신
- 로우 Lock 경합은 일반적으로 update나 delete 시에만 발생한다.
=> insert는 새로운 레코드를 삽입하는 것이므로 로우 Lock 경합이 발생하지 않는다.
=> But, Unique 인덱스가 정의되어 있을 때는 insert에 의해 row Lock 경합이 생길 수 있다.
- 두 개 이상 트랜잭션이 같은 값을 입력하려 할 때, 선행 트랜잭션이 아직 진행 중이라면 값의 중복 여부가
확정되지 않았으므로 후행 트랜잭션은 진행을 멈추고 대기 -> 대기 이벤트 발생
EX) 두개의 트랜잭션이 동시에 PK 인덱스가 생성돼 있는 컬럼에 접근하여 변경을 가하면 선행 트랜잭션이 커밋 / 롤백
할 때 까지 Share 모드로 row lock contention 대기 이벤트가 발생한다. TX1이 커밋하면 TX2는 무결성 제약조건(PK)에
위배된다는 에러(ORA - 00001)를 만난다.
EX) dept / emp 테이블이 1:M 관계이고, deptno 컬럼으로 dept.deptno를 참조하도록 emp 테이블에 FK 제약이 설정돼
있을때, 선행 트랜잭션이 dept에 deptno=40 을 지우고 후행 트랜잭션이 emp 테이블에 deptno=40 을 입력하면, 선행
트랜잭션이 커밋 또는 롤백할 때까지 Shared 모드로 row lock contention 대기 이벤트가 발생한다. 이때, 선행 트랜잭션이
커밋하면 후행 트랜잭션은 무결성 제약조건(FK)에 위배 된다는 에러(ORA - 02291)를 만난다.
- 비트맵 인덱스 엔트리에 대한 갱신을 수행할 때도 Share모드로 row lock contention 이벤트가 발생할 수 있다.
=> 하나의 엔트리가 여러 개 레코드와 매핑되기 때문에 하나의 엔트리에 Lock을 설정하면 매핑되는 레코드 전체에
Lock이 설정되므로 비트맵 인덱스 엔트리를 두 개 이상 트랜잭션이 동시에 갱신할 때 이벤트가 자주 발생한다.
(4) TX Lock -> ITL 슬롯 부족
- 블록에 레코드를 추가 / 갱신 / 삭제 하려면, ITL 슬롯을 먼저 할당 받고 그 곳에 트랜잭션 ID를 먼저 기록해야 한다.
=> 비어 있는 ITL 슬롯이 없다면, 사용중인 트랜잭션 중 하나가 커밋 또는 롤백할 때 까지 대기
=> 이 때, Shared 모드 allocate ITL entry 대기 이벤트 발생
- 한 블록을 동시에 갱신할 수 있는 트랜잭션 개수는 ITL 슬롯에 의해 결정된다. -> ITL 슬롯 : 24 byte
- 블록에 할당할 ITL 슬롯 개수는 INITRANS 파라미터로 설정
- PCTFREE 는 update문을 위해 예약된 공간이지만 INITRANS에 의해 미리 할당된 ITL 슬롯이 모두 사용중 이라면
=> PCTFREE에 의해 비워둔 공간을 활용할 수 있다.
=> 이 공간까지 활용해 최대 생성 ITL 슬롯 개수는 MAXTRANS로 결정
- ITL 슬롯 부족에 의한 대기현상 발생
1. 동시에 블록을 갱신하려는 트랜잭션 개수가 MAXTRANS 값을 초과
2. PCTFREE를 0으로 지정 / PCTFREE 예약 공간을 모두 사용한 상태에서 ITL 슬롯 부족
- 10g 에서는 MAXTRANS가 항상 255개로 고정된다.
- ITL 경합에 의한 대기 현상이 자주 발생하는 세그먼트(테이블, 인덱스, 파티션)에 대해서는 INITRNAS를 늘려주어야 한다.
=> 세그먼트 목록은 v$segstat를 통해 확인
- INITRANS 값을 변경하더라도 기존에 할당된 블록의 ITL 슬롯개수는 변함이 없으므로 기존 블록에서 ITL 경합이 빈번하게 발생한다면, 테이블 or 인덱스 전체를 재생성해 줘야만 한다.
- INITRANS 값은 중간에 변경 할 수 없다.
(5) TX Lock -> 인덱스 분할
- 인덱스는 정렬된 상태를 유지해야 하므로 아무 블록에나 값을 입력할 수 없다.
=> 값을 입력할 위치에 빈 공간이 없으면 인덱스 분할 (split)을 실시해 새 값을 입력할 공간을 확보 하게 된다.
=> 이 과정에서 Lock 경합이 발생할 수 있다.
EX) 중간에 낀 리프블록이 꽉찼다면 인덱스 분할을 실시하여 옆자리의 블록을 만들고 꽉찬 리프블록의 레코드 절반을 새로만든 블록으로 이동해야한다. 하지만 양끝단에 리프블록이 꽉찬 상태에서 새로운 입력을 받게 된다면 레코드를 옮길 필요 없이 블록하나만 만들어 주면된다. 문제는 인덱스 분할이 진행되는동안 그 블록에 새로운 값을 입력하려는 또 다른 트랜잭션이 생길 수 있다.
이 때, 두번째 트랜잭션은 선행 트랜잭션이 인덱스 분할을 완료할 때 까지 대기해야 하며 Shared 모드에서 Index contention 이벤트를 만나게 된다.
- 인덱스 분할 과정 중 대기 이벤트
1. 선행 트랜잭션이 인덱스에 로우를 삽입하려 하지만 빈 공간이 없다 -> 인덱스 분할 필요
2. 선행 트랜잭션은 autonomous 트랜잭션(후행)을 생성하여 인덱스 분할을 진행토록 한다.
3. 인덱스 분할이 진행중인 블록에 제3의 트랜잭션이 로우를 삽입하려고 한다.
=> 이때 제3의 트랜잭션은 index contention 이벤트를 만나고 후행 트랜잭션이 커밋할 때 까지 대기한다.
4. 인덱스 분할이 완료되면 후행 트랜잭션은 커밋하고 autonomous 트랜잭션이므로 선행 트랜잭션은 커밋할 필요가
없으므로 제3의 트랜잭션이 작업을 재개한다.
- PCTFREE 공간의 의미
1. Table : update 를 위해 남겨두는 공간
2. Index : insert 를 위해 남겨두는 공간
(6) TX Lock -> 기타 트랜잭션 Lock
- Shared 모드 contention : 분산 트랜잭션에서 2-Phase 커밋을 위한 PREPARED TX Lock을 대기할 때 발생한다.
- 읽기 전용 테이블 스페이스로 전환할 때 -> TX Lock 경합 발견
(7) TX Lock -> DML 로우 Lock
- DML Lock은 다중 사용자에 의해 동시에 액세스되는 사용자 데이터의 무결성을 보호해 준다.
- 로우 Lock은 두 개의 동시 트랜잭션이 같은 로우를 변경하는 것을 방지한다.
- 로우 Lock = 로우 단위 Lock + TX Lock
1. Undo 세그먼트에서 트랜잭션 슬롯 할당 받고
2. Enqueue 리소스를 통해 TX Lock 획득
3. insert / update / delete / merge 를 통해 갱신하는 각 로우마다 Exclusive 모드로 로우 단위 Lock 획득
4. TX Lock 은 트랜잭션을 시작할 때 한 번만 획득
- 로우 단위 Lock : 블록 헤더 ITL과 로우 헤더 Lock Byte 설정을 의미한다. 이를 통해 로우를 갱신 중인 트랜잭션 상태를
확인하고 액세스 가능 여부를 결정한다.
- TX Lock : Enqueue 리소스를 통해 TX Lock을 설정하는 것을 의미한다. Lock이 설정된 레코드를 갱신하고자 할 때
Enqueue리소스에서 대기한다.
(8) TX Lock -> DML 테이블 Lock (DML 문장 수행 시 자동으로 테이블 Lock 획득)
- 오라클은 로우 Lock 획득 시 해당테이블에 대한 테이블 Lock도 동시에 획득한다.
- 명시적으로 Lock Table 명령어 사용
1. lock table test in row share mode
2. lock table test in row exclusive mode
3. lock table test in share mode
4. lock table test in share row exclusive mode
5. lock table test in exclusive mode
- Lock 모드간 호환성 ('O' 표시는 두 모드 간에 호환성이 있음을 의미한다.)
- RS : row share (or SS : sub share)
- RX : row exclusive (or SX : sub exclusive)
- S : share
- SRX : share row exclusive (or SSX : share / sub exclusive)
- X : exclusive
=> 선행 트랜잭션과 호환되지 않는 모드로 테이블 Lock을 설정하려는 후행 트랜잭션은 대기하거나 작업을 포기해야 한다.
- insert / update / delete / merge 문을 위해 로우 Lock 을 설정하려면
해당 테이블에 RX 모드 테이블 Lock을 먼저 획득해야 한다.
- select for update 문을 위해 로우 Lock 을 설정하려면 RS 모드 테이블 Lock 을 먼저 획득해야 한다.
=> DML과 select for update 간 호환이 되므로 락 경합이 발생하지 않지만 같은 로우를 갱신할 때는 로우 락에 의한 경합은
발생한다.
- 오라클은 테이블 Lock(TM Lock)도 Enqueue로 구현하였다. -> TM Enqueue
- TM Enqueue 리소스 구조체의 식별자
1. TYPE : TM
2. ID1 : 오브젝트 ID
3. ID2 : 0
- 오라클에서 말하는 테이블 Lock은 Lock을 획득한 선행 트랜재션이 해당 테이블에서 현재 어떤 작업을 수행 중인지를
알리는 푯말(Flag)이다.
=> 푯말에 기록된 Lock 모드와 후행 트랜잭션이 현재 하려는 작업 내용(작업 범위)에 따라 진행 여부가 결정된다.
=> 진행을 포기할지 / 기다릴지 진로를 결정 -> 기다린다면 TM Enqueue 리소스 대기자 목록에 Lock 요청을 등록 후 대기
- Lock을 얻고자 하는 리소스가 사용중인 경우 프로세스가 취할 3가지 방법
1. select * from test for update : Lock 이 해제될 때까지 기다린다. => DML 문을 수행할 때
2. select * from test for update wait 3 : 일정 시간만 기다리다 포기한다.
3. select * from test for update nowait : 작업을 포기한다. => DDL 문을 수행할 때 NOWAIT 옵션이 자동으로 지정된다.
- 테이블 Lock 은 DML 간 동시성을 제어하려고 사용되기도 한다. -> 병렬 DML or Direct Path Insert 방식으로 작업을 수행
- 로우 Lock 호환성보다 테이블 Lock 호환성을 먼저 확인한다.
- TX Lock 은 트랜잭션마다 오직 한 개씩 획득하는 반면 TM Lock은 트랜잭션에 의해 변경이 가해진 오브젝트 수만큼 획득한다.
(9) Lock을 푸는 열쇠, 커밋
- 블로킹 (Blocking): Lock 경합이 발생해 특정 세션이 작업을 진행하지 못하고 멈춰 선 경우
- 교착상태 (Deadlock) : 두 세션이 각각 Lock을 설정한 리소스를 서로 액세스 하려고 마주보고 진행하는 상황을 말하며,
둘 중 하나가 뒤로 물러나지 않으면 영영 풀릴 수 없다.
- 오라클에서 교착상태가 발생하면 이를 먼저 인지한 세션이 문장수준 롤백을 진행한 후 에러 메시지(ORA - 00060)를 던진다.
=> 교착상태를 발생시킨 문장 하나만 롤백
=> 교착상태는 해소됐지만 블로킹 상태에 놓이게 된다.
=> 에러 메시지를 받은 세션은 커밋 or 롤백을 결정해야만 한다.
-> 예외 처리(commit or rollback)를 하지 않으면 대기상태가 지속된다.
- 트랜잭션을 길제 정의하지 않도록 주의해야 한다. (너무 오래 커밋을 날리지 않는 경우)
=> Undo 세그먼트가 고갈되거나 Undo 세그먼트 경합을 유발할 수 있다.
- 자주 커밋을 수행하면 Snapshot too old 에러를 유발할 가능성이 높아지고, LGWR가 로그 버퍼를 비우는 동안 발생하는
log file sync 대기 이벤트 때문에 성능 저하 현상을 겪을 수 있다.
- 잦은 커밋으로 인한 성능 저하 -> 오라클 10gR2부터 제공되는 비동기식 커밋 기능 활용
1. WAIT(Defualt) : LGWR가 로그버퍼를 파일에 기록했다는 완료메시지를 받을 때까지 대기,
그 동안 log file sync 대기 이벤트 발생 (동기식 커밋)
2. NOWAIT : LGWR의 완료 메시지를 기다리지 않고 바로 다음 트랜잭션을 진행
=> log file sync 대기 이벤트 발생 안함 (비동기식 커밋)
3. IMMEDIATE(Defualt) : 커밋 명령을 받을 때마다 LGWR가 로그 버퍼를 파일에 기록
4. BATCH : 세션 내부에 트랜잭션 데이터를 일정량 버퍼링 했다가 일괄 처리
첫댓글 2-phase commit : 데이터 백업을 위한 것, 본서버의 데이터를 바꾸면 분산되어 있는 데이터들을 바꿔주는 것