[SQL Server] Transaction

2022. 2. 12. 15:33TIL💡/Database

트랜잭션(Transaction)

- 업무 처리를 위한 논리적인 업무 단위

- 데이터를 일관성있게 처리하기 위해 여러 개의 갱신 연산이 하나의 작업처럼 전부 처리되거나 아예 하나도 처리되지 않도록(All or Nothing) 동시 실행 구현

 

1. 트랜잭션의 특징

🔮 원자성(Atomicity)

트랜잭션은 분해가 불가능한 업무의 최소단위이므로 전부 처리되거나 아예 하나도 처리되지 않아야 한다.

 

 

🔮 일관성(Consistency)

일관된 상태의 데이터베이스에서 하나의 트랜잭션을 성공적으로 완료하면 그 데이터베이스는 여전히 일관된 상태여야 한다.

즉 트랜잭션 실행의 결과로 데이터베이스 상태가 모순되지 않아야 한다.

 

🔮 격리성(Isolation)

실행 중인 트랜잭션의 중간결과를 다른 트랜잭션이 접근할 수 없다.

 

🔮 영속성(Durability)

트랜잭션이 일단 그 실행을 성공적으로 완료하면 그 결과는 데이터베이스에 영속적으로 저장된다.

 

2. 트랜잭션 격리성

Lock을 강하게 오래 유지할수록 강화되고, Lock을 최소화할수록 약화된다

가. 낮은 단계의 격리성 수준에서 발생할 수 있는 현상들

1) Dirty Read

- 다른 트랜잭션이 수정한 후 커밋되지 않은 데이터를 읽는 것

- 변경 후 아직 커밋되지 않은 값을 읽었는데 변경을 가한 트랜잭션이 최종적으로 롤백된다면 그 값을 읽은 트랜잭션은 비일관된 상태

 

2) Non-Repeatable Read

- 한 트랜잭션 내에서 같은 쿼리를 두 번 수행했는데, 그 사이에 다른 트랜잭션이 값을 수정/삭제하는 바람에 두 쿼리 결과가 다르게 나타나는 현상

 

3) Phantom Read

- 한 트랜잭션 내에서 같은 쿼리를 두 번 수행했는데, 첫 번째 쿼리에서 없던 유령(Phantom)레코드가 두 번째 쿼리에서 나타는 현상

-  두 쿼리 사이에 INSERT 트랜잭션이 발생했기 때문

나. 트랜잭션 격리성 수준(Isolation Level)

 

🔮Read Uncommitted

트랜잭션에서 처리 중인 아직 커밋되지 않은 데이터를 다른 트랜잭션이 읽도록 허용한다.

 

🔮Read Committed

트랜잭션이 커밋돼 확정된 데이터만 다른 트랜잭션이 읽도록 허용함으로써 Dirty Read 방지한다.

실제 테이블의 레코드 값을 읽는 것이 아니라 Undo 영역에 백업된 레코드에서 값을 가져온다.

하지만 커밋된 데이터만 읽더라도 Non-Repeatable Read와 Phantom Read 현상을 막지 못한다.

읽는 시점에 따라 결과가 다를 수 있기 때문이다.

 

1번 트랜잭션의 갱신(삽입/삭제/수정) 쿼리가 커밋되기 전에 2번 트랜잭션에서 SELECT 쿼리를 수행

👉 아직 커밋되지 않았기에 변경 이전의 데이터를 읽기

👉 하지만 1번 트랜잭션의 커밋 이후에 2번 트랜잭션에서 동일한 SELECT 쿼리를 수행하면 이전 데이터와 다른 데이터 읽기

👉 항상 같은 데이터를 가져와야 하는 데이터의 정합성이 깨진다.

👉 Non-Repeatable Read, Phatom Read 여전히 발생

 

🔮Repeatable Read

트랜잭션 내에서 쿼리를 두 번 이상 수행할 때 첫 번째 쿼리에 있던 레코드가 사라지거나 값이 바뀌는 현상 방지한다.

 

👉 Undo 공간에 백업해두고 실제 레코드를 변경

👉 MySQL 경우에는 트랜잭션마다 ID를 부여하여 현재의 트랜잭션 ID보다 작은 트랜잭션 번호에서 변경한 것만 읽음

👉 하지만 Phantom Read(첫 번째 쿼리에서 보이지 않던 유령 레코드가 두 번째 쿼리에서 보이는) 현상 여전히 발생

👉 다른 트랜잭션에서 삽입한 레코드가 나타날 가능성 존재하고 이를 방지하기 위해서는 쓰기 잠금 필요

 

🔮Serializable Read

트랜잭션 내에서 쿼리를 두 번 이상 수행할 때, 첫 번째 쿼리에 있던 레코드가 사라지거나 값이 바뀌지 않음은 물론 새로운 레코드가 나타나지도 않는다.

 

👉 가장 단순한 격리수준이지만 가장 엄격한 격리 수준

 

 

👉 Phantom Read현상이 발생하지 않음

👉 동시 처리성능이 가장 낮기에 잘 사용하지 않음

 

대부분 DBMS가 Read Committed를 기본 트랜잭션 격리성 수준으로 채택하고 있으므로 Dirty Read가 발생할까 걱정하지 않아도 된다.

그렇더라도 Non-Repeatable Read, Phantom Read 현상에 대해선 세심한 주의가 필요하다.

 

다중 트랜잭션 환경에서 DBMS가 제공하는 기능을 이용해 동시성을 제어하려면 트랜잭션 시작 전에 명시적으로 Set Transaction 명령어를 수행하면 된다.

ex) 트랜잭션 격리성 수준을 Serialiable Read로 상향

set transaction isolation level read serializable;

 

문제

👉 동시성

👉 대량의 데이터를 읽어 처리할 때는 동시성이 심각하게 낮아진다.

 

👉 완벽한 데이터 일관성 유지를 위해 심지어 테이블 Lock을 걸어야 할 때도 있다.

 

대안

 

👉 다중버전 동시성 제어(Multiversion Concurrency Control)

 

👉  = 스냅샷 격리성 수준(Snapshot Isolation Level)

 

👉 현재 진행 중인 트랜잭션에 의해 변경된 데이터를 읽고자 할 때는 변경 이전 상태로 되돌린 버전을 읽는 것

 

👉 읽는 세션과 변경하는 세션이 서로 간섭 현상을 일으키지 않음

 

참고

- https://nesoy.github.io/articles/2019-05/Database-Transaction-isolation

 

 

 

 

'TIL💡 > Database' 카테고리의 다른 글

[Redis] 데이터타입 실습2  (0) 2022.02.27
[Redis] Redis 학습 및 데이터 타입 실습1  (0) 2022.02.26
[SQL Server] Lock  (0) 2022.02.08
SQL Server로 Index 실습  (0) 2022.01.30
[데이터베이스] Index(인덱스)  (0) 2021.10.13