동시성 제어
실제로 concurrency하게 운용하며 conflict seriality 보장하려면 precedence 그래프 같은거론 불가능하다.
보통 아래와 같은 2가지 방법이 존재한다.
1) Lock 사용 하는 방법
2) lock 사용 x 방법( timestamp로 transaction의 순서 정하기)
Serial order
Lock: lock을 먼저 잡은 transaction이 앞 순서.
timestamp: “start” 시간으로 나열. 하지만 실제 concurrency 환경에선 시작 순서와 다르게 먼저 끝날 수 도>> 이런거 조심해야한다. Ex) serial order 대로 늦게 시작한 놈이 final write할수도
Lock
- 한시점에 1개 객체만 접근하는 것을 보장한다.
- Physical lock, logical lock 이 있지만, db에선 다르다.
- DB에선 보호하는 데이터의 범위가 다르다.
- Tuple, db 자체, 등등 너무 큰 범위.
- write시엔 1번에 1놈만. Read와 write에 대해 lock을 구분해야 함.
Exclusive lock VS shared lock.
Exclusive lock: 혼자만 접근 가능하게 (read,write )
Shared lock: shared 끼리 공유 가능 ( read 끼린 겹쳐도 된다)
Logical lock
데이터를 읽고 있는 동안, 다른 transaction이 update하는 것을 막기 위해.
concurrency manager(Lock manager) 에게 요청, manager가 보장해주면 다음 operation 진행.
Mem 직접 사용x manager 통해. Exclusive lock
내가 쓰려는데 누가 이미 lock 설정시 => 허용할지 말아야할지 판단 => lock compatibility Martrix
S X X: exclusive , S: shared lock
S T F
X F F
Lock 만으론 Serializable Order 보장 x
Display(A+B) 에서 unlock이 너무 빨리 실행, 그사이 바뀔 수 있다.
+@
해당 예제는 B에 대해 읽는 동안 다른 트랜잭션에 의해 A가 다른 값으로 write되면 문제가 된다는 것을 보여준다. T2는 자신이 읽은 A와 B의 합을 display하겠지만, 이는 저장된 값 (실제 ~이어야 하는 값)과 다를 것이다.
- 이것이 발생한 이유는 A+B를 display하기 훨씬 이전에 unlock(A)를 수행하여 A가 그 사이에 변화될 가능성을 남겼기 때문이다.
Locking protocol
모든 transaction이 lock을 요청, 해제 시 지켜야하는 룰. 스케줄에 제약을 걸어
Serializable하게한다.
Deadlock, Starvation의 case 2개 간단한 예시.
특정 transaction이 계속 발생 Or 다른 곳에서 lock 풀리기 전까지 무한대기
위에선 서로 자신이 lock을 건 data item을 놓지 않고 대기중. deadlock 생겨 T3,T4 모두 진전 x >> rollback 후 lock을 realease해야.
Starvation
S-lock 걸린 item에 대해 X-lock 걸고 사용하려고 대기 중인 T3. 만약 계속 누군가가 S-lock을 해당 아이템에 걸면, 해당 자원 계속 양보하여 T3는 계속 자원 할당을 받지 못한다>>
Concurrency control manager을 잘 디자인하면 방지 가능.
- 위 starvation을 막기 위해서 concurrency control manager는 다음의 경우에만 lock을 grant한다.
: 트랜잭션 T가 M mode의 lock을 Q에 대해서 요청할 때, M과 conflict한 mode의 lock을 가진 다른 트랜잭션이 없다면 (compatibility의 matrix에서 true이면) grant 한다.
: 트랜잭션 T가 M mode의 lock을 Q에 대해서 요청할 때, Q에 대해 T전에 요청하면서 wait하는 트랜잭션이 없을 때 grant한다. (X lock이 줄서고 있다면, S-lock은 잡을 수 있어도 대기.
Two-phase locking protocol
lock 만으로 conflict serializable 보장 x.
Conflict serializable 보장하기 위한 방법> 2PL.
각 프로토콜의 lock, un-lock 요청을 2단계로 진행
Growing phase: lock을 잡을 수 만 있다. ( 필요한 item 한 개씩 lock 걸어둔다.)
Shrinking Phase: lock을 풀 수 만 있다. (한 개 씩 놓는다.)
필요한 모든 lock을 얻은 지점: lock-point
2PL은 conflict serializablity 가능하게 하지만, cascading rollback, deadlock 문제 존재한다.
Two phase locking: Cascading Abort 문제
T2가 t1이 업데이트 한 값을 read하면, t1이 commit 될 때까지 T2도 대기 해야함. (recoverable)
(T1이 abort되어 업데이트 한 값이 무용지물 될 수 있다) >>대기했다가 연쇄적인 abort 발생
이는 strict 2PL로 해결가능
(둘 다 commit 시점에 lock을 한번에 놓아서 cascading 문제 방지)
Strict 2PL: transaction이 commit or abort 될 때까지 X-lock을 놓지 않는다.
( recoverability 유지 & cascading rollback 방지)
Rigorous 2PL: transaction이 commit or abort 될 때까지 모든 lock을 놓지 않는다.
두 방식 모두 transaction 들이 commit 시점을 serialized 된다.
lock conversion
2PL>> 초기에 lock을 한번에 잡는다.
T1이 growing phase에서 item X 에 대해 X-lock 잡았는데, write(X)가 T1의 마지막에 발생해서 Concurrency 나빠진다.
>> 우선 S-lock으로 걸어 놓고, 나중에 X-lock으로 전환하여 Concurrency 늘린다.
2PL의 lock protocol
Growing phase:
- 필요한 item의 X, S lock을 얻을 수 있다.
- S lock을 X lock으로 변경 가능 (upgrade) >> 우선 S lock 걸고 나중에 진짜 Write 시 X로 바꿔서 concurrency 증가시키기.
Shrinking Phase
-다 쓴 item의 X,S lock을 해제 할 수 있다
- X lock을 S lock으로 변경 가능 (downgrade)>> write 쓰고 나서, 다시 S lock으로 변경해 concurrency 증가.
Strict, rigorous 2PL + lock conversion 조합 자주 사용.( 한번에 풀고, S <> X lock 바꿔가며)
14p :Automatic Acquisition of lock: lock 자동화 해야 한다.
⦁ T1이 item D에 대해 Read 연산 발생 시
T1이 D에 대한 lock 보유 시 read(D) 수행
Lock 보유 x 시 D에 대한 모든 X-lock이 해제 될 때까지 대기 >> lock-S 걸고 read(D)
⦁ Write 연산 발생시
T1이 D에 대해 X-lock 보유 시 write(D) 수행
보유 x 시 D에 대한 모든 lock 해제될 때까지 대기
만약 T1이 D에 대해 lock-S 보유 시, X로 업그레이드
(미리 S-lock으로 걸어 논거 X lock으로 업그레이드)
Else T1이 D 에 대해 lock-X 걸기
write(X)
모든 트랜잭션 내의 모든 lock 은 commit or abort 시 해제 된다.
Lock manager
Lock manager은 독립적인 process로 동작한다.
transaction들이 lock, unlock 요청 메시지를 lock manager에게 전달하고,
lock manager은 그에 승인(lock을 걸어주며) or 거부를 통해 응답한다.
+만약 deadlock 발생 시, transaction에게 rollback을 명령한다.
Lock table
Lock manger가 관리하는 In-memory 데이터 structure.
Grant된 lock과 보류 중인 요청들을 기록한다.
주로 lock된 data item명으로 index된 in-memory hash table로 구현된다.
Linked list로 hash에 해당하는 영역에 도착한 request들을 저장한다.
Two-phase lock에서의 deadlock
lock간의 호환성을 그래프로 그려서 cycle 검사
해결법
⦁ Lock manager가 관리하는 lock들 중 Deadlock 발생을 주기적으로 check한다.
Wait for graph를 그려서 cycle이 발생하였는지 check한다.
⦁ Deadlock을 미리 방지한다(애초에 발생 x 하게).
Prioritize lock: Lock을 기다릴 때, 우선순위를 정해 놓는다. ( Serialize Order에서 순서 부여)
Prioritize lock
Wait-die: data에 접근 중인 transaction이 lock을 가진 transaction보다
먼저 들어왔으면 대기
나중이면 포기하고 나중에 다시 잡기
Wound-wait: 접근하려는 transaction이 lock을 가진 transaction보다
먼저 들어왔으면 lock 가진 transaction abort(rollback) 시키고 선점,
나중이면 wait
T1 > T2 의 순서: T1이 old, T2가 young
T1 / T2
Wait / die
Wound / wait
1번) T1(old) 이 T2(young)의 data 접근 요청 (먼저 놈> 나중 놈 요청)
-die : T1가 wait
-wait : T2를 abort 시키고 선점
2번) T2(young)가 T1(old)의 데이터 요청 ( 나중 놈> 먼저 놈 요청)
Wait- : T2가 스스로 abort 되고, 나중에 다시 온다.
Wound- : T2가 wait
Multiple granularity
여러 data item을 한 개의 lock으로 grouping하는 것이 좋을 때도 있다.
Ex) relation 전체 스캔 시, relation 전체에 1개의 lock을 거는 것이 tuple단위로 거는 것보다 좋다.
>> 다양한 lock 단위 granularity 필요
- lock 단위에 granularity 다르게 하는 것.
- 이는 데이터가 다양한 크기가 되도록 한다.
: 그리고 데이터 granularity의 계층을 정의한다.
: 여기서 작은 granularity는 더 큰 granularity 내에 있다. - 이는 트리 구조를 갖추게 된다.
- 하나의 노드에 명시적으로 lock을 거는 것은 암시적으로 이 노드의 후손 전체에 동일한 모드로 lock을 거는 것과 같다.
- locking의 granularity는 다음과 같은 특징을 보인다.
: fine granularity (lower in tree): 잘게 lock을 관리하게 되면, high concurrency를 보장하지만 관리해야 할 overhead가 증가한다. 즉 high locking overhead이다.
: coarse granularity (higher in tree): 큰 덩어리로 lock을 관리하게 되면, low concurrency와 low locking overhead
Record 단위로 lock을 사용, 여러 record에 대해 lock을 적용할 때.
Table 전체적으로 lock을 적용하면 되지만 어려워진다.
그 상위에 lock을 사용하게 되면 table 내 전혀 다른 작업에 대해서만
변경을 수행해도 concurrency가 크게 나빠진다( child들 모두 영향 받음).
Lock을 크게 잡을지(coarse) 작게(fine) 잡을지를 그때그때 선택해야한다.
T1이 Fc에 대해 X lock 잡고 있다면, Fc 하위 모든 요소들에 대해 lock을 잡고 있는 것.
Case 1) T2가 Fc 하위의 Rc1 에 lock 요청 >> root에서 rc1까지 scan, 하나라도 충돌하는 lock이 걸려있다면 대기.
Case 2) T3가 Db 전체에 lock 요청 >> Db에 대한 전체 트리를 scan, 하나라도 충돌하는 lock이 걸려있다면
대기.
매번 child들을 확인해야하는 문제.
>> intention lock 이 해결책
intention lock
하위에 어떤 정보가 x-lock or s-lock 으로 잡혀 있다, 라는 것을 알려준다.
: intention-shared (IS) - 하위에 S-lock이 존재한다는 걸 명시한다.
>>해당 노드 하위 리소스 중 일부에 Read 수행하기 위해
: intention-exclusive (IX) – 하위에 S or X lock 존재를 명시한다.
>>해당 노드 하위 리소스 중 일부에 write 수행하기 위해
SIX ( shared and intention-exclusive)
>> 해당 노드와 하위 전체에 대해 read를 수행하고, 일부는 write 할시.
어떤 Transaction이 대부분 Read작업을 하는 가운데, 일부(ex. a few tuple)를 write 작업을 하려고 할 때,
처음부터 단번에 SIX락을 걸고 read 와 write 작업을 하게 되는 것.
따라서, IS락을 건 상태에서 자식의 일부에 read작업을 하다가 IS락이 걸려있는 노드에 SIX락을 걸고, 자식에 아무 작업이 없는 노드에 X락을 걸고 작업을 할 수 있다는 것입니다.(이런 병행성 보장을 위해서 SIX락이 나온 것
스스로 shared lock (본인에 관한)+ IX lock (child에 관함)
하위에서 lock을 잡으면, 상위에 자동으로 intention lock 추가.
IS, IX >> 만약 지금 당장 100% 문제되는지 알 수 없으면 true!!
IS <> IX >> child에 있는 거, 당장은 문제되는지 모름 > true
IS <> X >> X를 걸어버리면, 하위의 모든 lock에 X lock 거는것과 동일.
하지만 IS >> 하위에 S lock 존재를 암시함으로 불가.
SIX <> IX >> SIX : 자기자신에 S-lock 따라서 하위에 모두 최소 S-lock, (X lock도 섞여있는것.)
>> IX는 하위에 X lock 암시> 모두 최소한 S lock 걸려있으니 불가.
SIX <> S >> SIX: 적어도 1개 X lock 존재 , S: 모두 S lock 따라서 불가!
Ti 가 노드 Q에 lock을 걸기 위한 규칙
⦁ 호환되는 matrix가 관찰되야 한다.
⦁ Root가 가장 먼저 lock되야 한다.
⦁ - 트랜잭션 Ti는 Ti가 최근에 Q의 부모를 IX 혹은 IS 로 걸어 놨어야
S, IS 모드로 잠글 수 있다. (내려가기 전에 미리 암시하기.)
⦁ - 트랜잭션 Ti는 Ti가 최근에 Q의 부모를 IX 혹은 SIX 로 걸어 놨어야
Q를 X, IX 혹은 SIX로 잠글 수 있다.
⦁ - 트랜잭션 Ti는 최근에 un-lock을 안해야만 lock 가능 (2PL)
⦁ - 트랜잭션 Ti는 최근에 Ti 자신이 Q의 child들에게 lock을 걸지 않았을 때만 Q를 unlock 가능.
Lock acquire 은 root> leaf 순서로
Lock release는 leaf> root 순서로
만약 특정 계층에 lock이 너무 많이 걸려있다면, S, X lock 같은 higher granularity 가진 lock으로 바꾸자. ( lock이 필요 없는 노드까지 걸려도, 그냥 한번에 lock 거는 것이 좋을 수도)
여태까진 transaction이 read, write 를 통해서만 date item에 접근한다고 가정했다.
- 하지만 실제론 date item에 대해 insert, delete 연산도 고려해야한다!
- Insert, delete 시 X lock 걸고 해야한다
Delete: 삭제 전에 삭제할 놈에게 X-lock ( R-W conflict 방지)
Insert: tuple 을 insert 하면 insert한 것에 대해자동으로 X-lock이 걸린다.( 해당 tuple을 insert하는 transaction이 commit 되기 전까진 접근 불가!)
팬텀 현상
Insert, delete, update 시 고려 시 문제 : 팬텀 현상(서로 다른 data item에 대해서도 conflict 생김
T1이 Relation r 스캔(predicate read) 중 T2가 R에 튜플을 insert하면?
⦁ 만약 T1이 T2가 insert한 튜플도 스캔해야 하면, T2가 serial한 순서상 먼저 와야한다.
⦁ T1이 T2가 insert한 튜플을 스캔하지 않는다면, T1이 serial한 순서상 먼저 와야한다.
만약 tuple lock만 사용시, 이런 문제는 발견되지 않는다. ( 팬텀현상)
중간에 update 시에도 똑같은 문제.
팬텀 현상 해결책
Data item과 relation을 연관 지어 relation이 가지고 있는 tuple 정보를 표현한다.
(relation 자체에 lock 을 걸어버리는 것)
Relation을 scan하는 transaction가 data item에 S-lock 걸기
Relation에 tuple을 insert나 delete 하는 transaction이 해당 date item에 X-lock 걸기.
>> 위 방식들은 Concurrency가 너무 낮아진다.
(서로 다른 튜플을 같은 relation에 동시에 넣는 연산이 불가능 해진다.)
Index-locking protocol 으로 팬텀 현상 방지
motivation: count(*) 등을 담는 데이터에 대한 locking은 두개의 트랜잭션이 동시에 insert하는 것을 막는다. 즉, concurrency 정도를 낮춘다. ( count는 relation안 모든 data에 접근하기에)
1) 모든 릴레이션은 반드시 적어도 하나의 인덱스를 가진다.
2) 트랜잭션은 relation의 하나 이상의 인덱스를 통해 튜플을 찾은 후에만 액세스할 수 있다.
relation 스캔은 인덱스 중 하나의 모든 리프를 통과하는 스캔으로 처리된다
3) lookup을 수행하는 트랜잭션 Ti는 자신이 접근하는 모든 인덱스 leaf 노드를 S-mode로 잠가야 한다.
4) relation r에 tuple의 insert, delete, update를 수행하는 transaction은
- r의 모든 index를 업데이트 해야한다.
-insert, delete, update에 영향을 받는 모든 index leaf 노드에 X-lock을 걸어야한다.
트랜잭션 Ti는 r에 대한 모든 인덱스를 update하지 않고 릴레이션 r에 튜플 ti를 삽입할 수 없다. Ti는 반드시 영향을 받는 모든 인덱스 leaf에 대한 X-mode lock을 얻어야 한다.
5) 2PL의 규칙은 반드시 준수되어야 한다.
요약: relation 수정하는 transaction은 수정에 영향 받는 모든 인덱스에 X-lock
Relation을 scan하는 transaction은 scan하며 접근하는 모든 index의 leaf에 S-lock
>> 팬텀 현상 완전 방지.
단순히 table lock으로도 가능하지만 concurrency 크게 떨어짐.
timestamp방식
Transaction의 안전한 순서를 timestamp로 보장하는 방식.
Counter는 계속해서 증가한다. >> 이 counter로 오래된 transaction과 이후에 비교적 새로운 transaction 구분.
TS( time stamp)
TS(T I ) < TS(T j ) 일시 T j가 더 나중.
이론적으로 이런식으로 각 transaction의 순서 결정 가능하다.
Read, write 에 대한 timestamp를 데이터에 추가적으로 남긴다.
W-timestamp(Q) :Q에대해 Write 할 때마다 W-timestamp가 가장 TS 큰 값( 최신값) 마크
R-timestamp(Q) :Q에대해 Read 할 때마다 W-timestamp가 가장 TS 큰 값( 최신값) 마크
read, write 발생시 timestamp 기준으로 확인 후 안전 x 시 abort.
내 TS >= timestamp 여야 된다!! (내가 최신이어야 한다!)
T(transaction)가 read(Q) 발생시킬 때
Ts(T)<W-timestamp(Q) 일시 ( 더 뒤에 올 놈이 먼저 된 것)
>>read하면 안된다. > T가 abort된다. (T가 원했던 Q가 새롭게 write 됬기에)
Ts(T)>=W-timestamp(Q)일시 (RR은 가능하기에 R stamp는 고려 x)
>>read 가능
R-timestamp(Q)를 max(TS(T),R-timestamp(Q)) 로 세팅
T가 write(Q)
⦁ TS(T) < R-timestamp(Q) >> T rollback ( T가 write하는 Q가 이전에 필요했던 값)
⦁ TS(T)<W-timestamp(Q) >> T rollback (old 값을 write하려고하기에)
⦁ 위 두 케이스 제외하면, write 후 W-timestamp(Q)를 TS(T)로 세팅.
예시
위는 ok, 아래는 abort 발생.
Timestamp 방식은 serializability가 지켜진다. ( precedence 그래프에 cycle x)
- deadlock(영원한 wait) 발생 x 하지만 긴 transaction에 대한 starvation은 발생 가능.
만약 위의 abort되는 케이스에서 abort하지 않고 T27을 그냥 둔다면?
=>마지막 write 통해 overwrite만 하지 않으면 문제가 없다.
TS(T) < timestamp(Q) 라면, 오래된 값을 write 하려고 하는 것이기에, 하면 안된다.
이때 abort (이후 rollback) 하는 대신에, write연산만 무시하자! ( old write: T27 write 무시)
(T27 이 먼저 시작함. 실제론 concurency하게 왔다갔다하지만, 첫 의도는 각 transaction 별 순서
T27 > T28 이므로, overwrite 시에 T28의 write가 마지막에 와야 한다.
만약 T27 을 abort했다면 , 결과적으로 1개 transaction만 실행한거니까
Concurrenct 1 ( 동시에 1개)
Abort x 시 concurrency 2
Tomas write Rule 사용시 concurrency 증가 가능. (View serializable이고 conflict serializable x 인거 허용) 즉, RW 케이스를 배제하는 것.
T1 이 먼저 시작, 이후 T2 이기에, serial 순서는 T1> T2 다.
따라서 final write는 T2의 write여야한다.
하지만 T2 가 먼저 commit됨. >> T1의 write는 수행x하고, 별도 공간에 저장하고, abort x
Runtime: lock 사용
Lock은 온전한 Serializable Order 위해 과하게 Concurrency 제한함.
( 애초에 안꼬이게)
Timestamp: 다 해놓고 timestamp로 문제 되나 check, 문제되면 고치기.
Db: 가장 안전한 방법은 Two Phase(2PL) 방식.
Validation
각 사용자는 자기 혼자 시스템 사용하는거로 생각하고 수행
Transaction 수행 중에 다른 transaction이 data 변경하면 안됨.
>> 여러 사용자가 있음에도, 여러 사용자의 transaction을 순서대로 처리하면
문제를 방지가능.
실제 transaction을 순차적으로 처리하면 성능이 나빠진다.
Lock: 서로 다른 transaction이 동일 data 접근 시 lock.
Lock을 얻게되는 순서로 transactoin간의 순서, serilization order을 얻을 수 있다.
2PL 중요.
Timestamp로 serializable order 결정 가능. 특정 이벤트에 따라 증가하는 카운터로 순서.
Timestamp: 2가지 프로토콜
Timestamp를 하나씩 발급하고, 트랜잭션마다 실행 시작 시점으로 순서 결정
Timestamp를 사용해서 순서를 결정해도, 문제 발생 가능성이 있다.
경우에 따라 abort or commit.
<Timestamp 리뷰>
Timestamp ordering 각 transaction 시작마다 새로운 timestamp.> 이에 serialization order을 미리 결정하고 동시에 수행한다. 이 때, 미리 결정된 순서대로 잘 되면 그대로, 아니면 abort 후 다시.
Transaction이 동시에 수행 되었을 때 문제: transaction이 순서대로 x 기에 더 나중에 될 놈이 먼저 될 수 도…. 다른 transaction이 미리 업데이트 한 값이 존재한다고 하면, 미래에 있어야할 데이터를 미리보는 것>> 문제!!
Write 역시 마찬가지. 쓰려는 값이 있는데, 그 값이 나보다 나중에 시작하는 transaction의 데이터를 읽어왔다면, 논리적으로 문제!
내 transaction 다음 transaction이 미리 기록해버리는 것도 logical하게 문제! ( 최종 값이 달라진다)
이런 문제를 확인하고, 트랜잭션 중단 후 다시하는 validation 과정이 필요하다.
timestamp ordering은 실제에선 별로다.
단점
Data read를 하고 있음에도, R-timestamp를 write해야한다.
(read 에 추가로 write가 발생하는 것.)
Read 보다 write가 무겁다.
Read는 순서가 중요 x 여러 transaction이 동시에 읽는 것에 제약 x
하지만 write는 순서에 제약 있다. 동시성이 낮다!
장점:
deadlock은 발생 x,
but starvation 문제는 존재
긴 트랜잭션 T1, 짧은 트랜잭션 T2, 순서가 T1> T2일시
T1이 남긴 데이터를 T2가 봐야한다. 따라서 T1의 긴 트랜잭션이 끝날 때까지 T2는 계속 abort를 반복.
(짧은 T2트랜잭션이 먼저 commit >> recoverable한 상태가 아니기에 안된다. )
T2가 먼저 끝나도 T1이 commit인지 ,abort인지 따라 T2가 진짜 성공인지 아닌지 알 수 있다.
따라서 T1이 끝날 때까지 T2가 기다린다..
토마스 write rule: 순서대로 수행되야할 트랜잭션에서, 나중에 와야 할 트랜잭션이 먼저 수행되면,
원래는 abort해야하지만, write만 skip한다.
Validation base protocol
실행 순서를 미리 결정하지 않고, 각자 스케줄이 되는대로 진행했다가, 마지막에 수행 결과가 올바른 serialization order 만들면 commit, 아니면 abort 수행한다.
(마구잡이로 해놓고, commit 시점에서 유효하면 commit 아니면 abort 하는 것)
Conflict가 적은 환경, 서로 꼬일 가능성이 없는 read 가 많은 상황에서 좋다!
Concurrency control 기법을 2가지 카테고리로 나누면
⦁ 안전한 순서를 미리 만드는 방법. ( prevent)
⦁ 문제가 없을 거라 가정하고 각각 진행한 뒤, 문제되면 그때 중단하는 방법.
=Optimistic concurrency control : 접근 순서가 문제가 되더라도, 각 transaction이 serialize 순서를 만들 수 있다면 ,접근 순서 제약 없이 좋은 결과를 만들 수 있다.(concurrency가 좋아진다!)
Optimistic 이 성능이 나은 경우가 은근 많다!
유리한 환경: read 위주 or conflict 적은 환경에서 good!
⦁ 은 conflict 가 없더라도 lock 등으로 순서 제약하고, read 도 lock 걸어서 read 위주여도 성능 bad.
Optimistic이 나쁜 경우도 존재: 해보고 아니면 전체를 버려야함. 트랜잭션이 매우 길면
한참 구한 값을 다 버려버린다. (1)의 방지하는 방법이 훨씬 덜 버리기에 이점에서 이점있다.
Validation base protocol: 타임 스탬프를 사용한다.
하지만 기준이 timestamp 시작이 아닌, commit 시점에서 serilize order를 만들 수 있는지 확인한다. 즉 commit 시간으로 serilize order 생성.
트랜잭션 중간의 write 미리하지 않고, commit 시점 근처에서 write 수행
( commit 시점에 결정하려면, commit보다 한참전에 write 발생하면 복잡해진다)
이 시점에 validation으로 문제가 없는지 확인한다
문제 있나 기준: 뭘 read, write했는지 보는 read, write set 필요.
(read, write set 관리해야)
Validate( commit 시점) 순서가 serial order. T25 > T26이다.
T25에서 validate phase 도착시 빨간영역( validate 전까지) 사이에 validation 종료된 transaction을 확인하고, 있다면 read, write set을 서로 비교해서 겹치는 값이 있나 확인. 겹치면 abort, 겹치지 않으면 그대로 commit(단 Read, Read는 겹쳐도 된다..
T25> 빨간영역 사이에 종료된 transaction x 기에 commit!
T26의 validate phase: 파란영역 사이에 T25가 종료됨. 따라서 T25의 read, write set 과 대조
T25 >> Read: A,B ,Write :X
T26>> Read: A,B ,Write:X
Read 끼리는 겹쳐도 된다. 따라서 성공! ( write와는 1개라도 겹치면 안된다)
Validation: 일단 된다고 치고 , commit 근처 Validation단계에 검증!
'데이터베이스(rebooting now)' 카테고리의 다른 글
[db] recovery system (1) | 2022.12.27 |
---|---|
[db] transaction (1) | 2022.12.27 |
[db] query optimization (1) | 2022.12.27 |
[db] query processing (1) | 2022.12.26 |
[db] indexing part-2 (B+ Tree) (0) | 2022.12.26 |