이전 글을 보고 오면 아래 내용을 더 편하게 읽을 수 있다.
2025.11.18 - [데이터베이스 시스템] - [DB System 이론] Transaction & Conflict Serializability
[DB System 이론] Transaction & Conflict Serializability
transaction은 기본적인 하나의 실행 단위이다.DB에서는 SQL문 하나라고 생각할 수 있다. 트랜잭션의 4가지 속성(ACID)아래의 예시를 생각해보자. 1.DB에서 A계좌 정보를 읽어온다.2.A잔액을 50달러를 뺀
april2901.tistory.com
Testing for Conflict Serializability
어떤 schedule이 conflict serializable, 즉 안전한지 아닌지 알아보는 법을 생각해보자.
실제로 conflict하지 않은 각 instructions들을 계속 바꿔보며 serial하게 바꿀 수 있는지 파악하는 것은 너무 시간이 많이 든다.
그래서 serializable여부를 빠르게 파악하기 위해 precedence graph를 사용한다.
<precedence graph>

그래프의 노드는 트랜잭션을 의미한다.
여러 트랜잭션들 사이에서 conflict가 나는 instruction들이 있다면, instruction들 중 시간순으로 가장 먼저 나오는 instruction이 있는 트랜잭션으로부터 다른 트랜잭션으로 화살표를 긋는다.
사이클이 있으면 두 트랜잭션 중 하나를 온전히 먼저 실행할 수 없기 때문에 serializable하지 않다.
T1의 어떤 명령어가 T2의 어떤 명령어보다 먼저 실행되어야하는데, T2의 다른 명령어는 T1의 또 다른 명령어보다 먼저 실행되어야하는 것이기 때문이다.
결국 트랜잭션 하나를 끝내고 다른 트랜잭션을 실행하는 serial한 스케줄은 불가능하다.
만약 사이클이 없다면 어떻게든 순서를 조정하여 serial한 스케줄을 만드는 것이 가능하다.
precedence graph로 사이클이 없는, acyclic한 그래프가 그려졌다면, topological sort를 이용해 스케줄을 구성할 수 있다.
아래 예시를 통해 알아보자.
두 트랜잭션의 명령어들 중 같은 변수에 대해 write연산이 한쪽에라도 있다면 conflict하기 때문에
이 점을 이용해 precedence graph를 그릴 수 있다.

recoverable schedule
먼저 아래같은 스케줄이 있다고 하자.
여기서 commit명령어는 저번 글에서 봤던 transaction state의 committed 상태로 넘어간다는 명령어이다.
즉 사용자에게 트랜잭션이 잘 실행되었다고 알림이 간다는 소리다.

위 스케줄은 문제가 있다.
T8에서 read(B)를 하다가 어떤 문제가 발생하면 atomicity 보장을 위해서 nothing상태로 만든다.
즉 T8이 실행되지 않았던 것처럼 rollback을 한다.
그러면 T9는 write도 안된 값을 읽어서 이미 사용자한테 보내버린게 된다.
T8이 없었던 일이 되었으니 T9도 없었던 일처럼 해줘야하는데 이미 사용자에게 간 알림은 주워담을 수 없기 때문에 문제가 발생한다.
이런 스케줄을 recoverable하지 않은 스케줄이라고 한다.
이런것까지 고려된 스케줄을 구성할 필요가 있다.
위 예시에서는 T8이 commit 하기 전에 T9가 commit을 못하게 만들면 된다.
이러면 T8이 rollback하더라도 T9도 rollback이 가능해진다.
일반화 하면, write가 있는 트랜잭션의 commit 이후 read가 있는 트랜잭션의 commit이 발생하면 된다.
Cascading rollback, Cascadeless schedule
아래의 스케줄도 한번 살펴보자.

열심히 잘 실행해놓고 마지막에 T10에서 abort가 나와버렸다.
즉 'T10을 없었던 일로 하자'는 말이 나온 것이다.
T10을 rollback하면 연달아 T11과 T12도 rollback해야한다.
여기서 문제는 성능이 떨어진다는 것이다.
이런 현상을 cascading rollback이라고 하고, 이런 일을 발생하는 않는 스케줄이 cascadeless schedule이다.
이를 막으려면 다른 애가 write를 하고 commit 까지 끝냈을 때 read를 하면된다.
commit 하면 이미 엎질러진 물이 되어버리므로 rollback(주워담기)가 안되기 때문이다.
<정리>
스케줄은 필수적으로 conflict serializable과 recoverable해야한다.
또한 필수는 아니지만 성능을 위해 Cascasdeless schedule이 권장된다.
Weak Levels of Consistency
위의 조건들은 매우 까다롭다.
그래서 가끔은 낮은 수준의 엄격함이 사용되어도 괜찮아 보이는 경우들이 있다.
예를 들면 통계수치를 다룰 때이다. 값 하나가 이상하다고 전체를 rollback하거나 다른 조치를 하지 말고,
전체 데이터 중에 값 하나는 통계에 미미한 영향을 끼치므로 그냥 넘어가는 경우가 있다.
성능과 정확성의 trade off라고도 할 수 있다.
표준 SQL은 이 정도를 직접 정할 수 있다.

< phantom phenomenon >
한가지 골치 아픈 문제를 잠깐 알아보자.
아래의 두 트랜잭션을 보면 실행 순서에 따라 결과가 달라지므로 conflict이다.
T1: selectID, name from instructor where salary>90000;
T2: insert into instructor values('11111', 'James', 'Marketing', 100000);
그러나 precedence graph에서 conflict를 탐지하는 방법은 같은 값(sql에서는 튜플)에 대한 변경을 살피는 것이기 때문에,
위 예시는 포함되지 않는다.
왜냐하면 같은 값에 대한 다른 명령어가 아니라, 새 값을 추가하는 것이기 때문이다.
phantom phenomenon는 이렇게 그래프에서 탐지되지 않는 conflict를 얘기하는 현상이다.