RDB

postgreSQL - 트랜잭션 격리 수준

hs-archive 2023. 12. 5. 00:11
공부 내용을 정리한 글입니다. 틀린 내용이 있을 수 있으니 아래 첨부한 공식 문서를 참조하세요.

 

PostgreSQL의 트랜잭션 격리 수준

pg는 총 네 가지 격리 수준(Read uncommitted, Read committed, Repeatable read, Serializable)을 제공하지만, 내부적으로는 read committed, repeatable read, serializable 세 가지 격리 수준으로 동작합니다. 공식 문서에 따르면 표준 격리 수준을 PostgreSQL MVCC와 매핑하는 유일한 합리적인 방법이라서 그렇게 제공한다고 말하고 있습니다.

 

pg는 트랜잭션의 격리 수준을 구현하기 위해 MVCC를 사용합니다. MVCC란 특정 시점을 기준으로 "커밋된" 데이터를 읽는 것입니다. 반면, read uncommitted는 "커밋되지 않은" 값을 읽는 것입니다. 이것이 MVCC를 사용하는 pg가 내부적으로 read uncommitted를 제공하지 않는 이유라고 생각됩니다.

 

pg의 Isolation level과 이상현상

 

위 표를 보면 알 수 있듯 pg에서는 read uncommitted 모드에서 dirty read가 발생하지 않습니다. 이는 pg에서는 read uncommitted가 내부적으로 read committed로 동작하기 때문입니다. 또한, 아래에서 설명해 드릴 특성 덕분에 pg에서는 repeatable read에서 phantom read가 발생하지 않습니다.

 

pg는 내부적으로 read committed, repeatable read, serializable 세 가지 격리 수준만 있기 때문에 이 세 가지 격리 수준에 대해서만 알아보겠습니다.

 

Read Committed Isolation Level

read committed는 pg의 기본 격리 수준입니다. 이 격리 수준을 사용하는 경우 (FOR UPDATE/SHARE가 없는)SELECT 쿼리는 해당 쿼리가 시작되기 전에 커밋된 데이터만 볼 수 있으며, 다른 트랜잭션에서 변경 중인 커밋되지 않는 데이터나 쿼리 실행 도중에 다른 트랜잭션에서 커밋이 된 데이터는 볼 수 없습니다.

 

해당 쿼리가 시작되기 전에 커밋된 데이터를 보므로, 두 개의 연속된 SELECT 명령이 단일 트랜잭션 내에 있더라도 첫 번째 SELECT 명령 다음에 다른 트랜잭션이 변경 내용을 커밋하고 그 다음 두 번째 SELECT 명령을 날리면 첫 번째 SELECT와 두 번째 SELECT의 결과가 다를 수 있습니다. (non-repeatable read가 발생할 수 있다는 것)

 

UPDATE, DELETE, SELECT FOR UPDATE/SHARE 명령 또한 명령 시작 시간을 기준으로 커밋된 대상 행만 찾습니다. 그러나 이러한 대상 행을 찾을 때 이미 다른 동시 트랜잭션에 의해 업데이트되었거나 삭제 혹은 잠겨있을 수 있습니다. 이 경우 먼저 시작한 트랜잭션(first updater)이 커밋되거나 롤백 될 때까지 기다립니다.

 

first updater가 롤백 되면, first updater가 했던 작업은 무효화되고, 두 번째 업데이터(second updater, 현재 read committed 격리 수준으로 동작 중인 UPDATE, DELETE, SELECT FOR UPDATE, SELECT FOR SHARE 명령을 수행하는 트랜잭션) 는 원래 발견했었던 행을 업데이트하면 됩니다.

 

first updater가 커밋되었을 때는 두 가지로 나누어서 생각할 수 있습니다. 우선 first updater가 행을 삭제한 경우 second updater는 해당 행을 무시합니다. 반면, first updater가 행을 삭제하지 않은 경우 second updater는 행의 업데이트된 버전이 명령의 검색 조건(WHERE 절)에 의해 여전히 동일하게 검색되는지 확인하고, 여전히 동일하게 검색되는 경우 업데이트된 버전의 행을 사용하여 작업을 진행합니다.

 

Repeatable Read Isolation Level

repeatable read 격리 수준은 트랜잭션이 시작되기 전에 커밋된 데이터만 볼 수 있으며, 트랜잭션이 실행되는 동안 커밋되지 않은 데이터나 동시 트랜잭션에 의해 커밋된 변경 사항은 볼 수 없습니다. 이는 SQL 표준에서 해당 격리 수준에 대해 요구하는 것보다 더 강력한 보장이며, serializable anomaly를 제외한 모든 현상을 방지합니다. (트랜잭션이 시작되기 전에 커밋된 데이터를 기준으로 작업을 수행하므로 phantom read가 발생하지 않습니다)

 

이 격리 레벨은 repeatable read 트랜잭션의 쿼리가 트랜잭션 내의 현재 statement의 시작 시점이 아니라 트랜잭션의 첫 번째 비 트랜잭션 제어문 시작 시점의 스냅샷을 본다는 점에서 read committed와 다릅니다.(read committed는 각 쿼리 시작 시점을 기준으로 커밋된 데이터를 보고, repeatable read는 트랜잭션 시작 시점을 기준으로 커밋된 데이터를 보는 차이를 말하는 것) 따라서 자신의 트랜잭션이 시작된 이후에 커밋된 다른 트랜잭션에 의해 변경된 내용을 볼 수 없습니다.

 

UPDATE, DELETE, MERGE, SELECT FOR UPDATE, SELECT FOR SHARE 명령 또한 트랜잭션 시작 시간을 기준으로 커밋된 대상 행만 찾습니다. 그러나 이러한 대상 행을 찾을 때 이미 다른 동시 트랜잭션에 의해 업데이트되었거나 삭제 또는 잠겨있을 수 있습니다. 이 경우 repeatable read 트랜잭션은 첫 번째 업데이트 트랜잭션(first updater)가 커밋되거나 롤백 될 때까지 기다립니다.

 

first updater가 롤백 되면 first updater가 했던 작업은 무효화되고 second updater는 원래 발견했었던 행을 업데이트합니다.

 

first updater가 커밋되었을 때 repeatable read 격리 수준의 트랜잭션은 아래와 같은 메시지와 함께 롤백 됩니다.

 

"ERROR:  could not serialize access due to concurrent update"

"오류: 동시 업데이트로 인해 액세스를 직렬화할 수 없습니다."

(만약 repeatable read 트랜잭션이 다른 트랜잭션에 의해 변경된 행을 수정한다면 lost update가 발생할 수 있으므로, 아예 롤백시키는 것입니다)

 

이처럼 repeatable read 수준은 직렬화 실패를 던지는 가능성이 있으므로, 이 수준을 사용하는 애플리케이션은 직렬화 실패가 발생할 때를 대비하여 트랜잭션을 재시도할 준비가 되어있어야 합니다.

 

Serializable Isolation Level

Serializable 격리 수준은 가장 엄격한 트랜잭션 격리를 제공합니다. 이 수준은 모든 커밋된 트랜잭션에 대해 직렬 트랜잭션을 에물레이션하여서 마치 트랜잭션이 동시에 실행되는 것이 아니라 순차적으로 실행되는 것처럼 보이는 격리 수준입니다.

 

이 격리 수준은 repeatable read 수준과 완전히 동일하게 작동하지만, 직렬화 가능한 트랜잭션의 동시 실행이 해당 트랜잭션의 가능한 모든(any) 직렬(한 번에 하나씩) 실행과 일치하지 않은 방식으로 작동할 수 있는 조건을 모니터링한다는 점이 다릅니다. (repeatable read랑 다 똑같은데, 단 한 가지, repeatable read에서 발생할 수 있는 이상 현상들을 감지하기 위해 모니터링 기술이 들어간다는 것이 다르다는 말입니다)

 

이 모니터링 기술은 반복 읽기에서 발생하는 것 이상의 차단을 일으키진 않지만, 약간의 오버헤드가 있으며, serialization anomaly가 발생할 수 있는 조건이 감지되면 직렬화 오류를 발생시킵니다. 따라서 repeatable read와 마찬가지로 이 수준을 사용하는 애플리케이션은 직렬화 실패가 발생할 때를 대비하여 트랜잭션을 재시도할 준비가 되어있어야 합니다.

 

pg에서는 Serializable 격리 수준을 위해 serializable snapshot isolation를 구현했으며, 해당 기술은 SIRead Lock를 포함한 다양한 기술을 통해 구현되었습니다.

 

참조

 - SSI

 - Serializable

 

 

 

 

 


https://wiki.postgresql.org/wiki/SSI

 

SSI - PostgreSQL wiki

Documentation of Serializable Snapshot Isolation (SSI) in PostgreSQL compared to plain Snapshot Isolation (SI). These correspond to the SERIALIZABLE and REPEATABLE READ transaction isolation levels, respectively, in PostgreSQL beginning with version 9.1. O

wiki.postgresql.org

https://wiki.postgresql.org/wiki/Serializable

 

Serializable - PostgreSQL wiki

Information about the SSI implementation for the SERIALIZABLE transaction isolation level in PostgreSQL, new in release 9.1. Overview With true serializable transactions, if you can show that your transaction will do the right thing if there are no concurr

wiki.postgresql.org

https://www.interdb.jp/pg/pgsql05.html

 

The Internals of PostgreSQL : Chapter 5 Concurrency Control

 

www.interdb.jp

https://www.postgresql.org/docs/current/transaction-iso.html#XACT-SERIALIZABLE

 

13.2. Transaction Isolation

13.2. Transaction Isolation # 13.2.1. Read Committed Isolation Level 13.2.2. Repeatable Read Isolation Level 13.2.3. Serializable Isolation Level The SQL standard …

www.postgresql.org

'RDB' 카테고리의 다른 글

MySQL vs MariaDB  (0) 2024.01.18
이미지는 어디에 저장해야 할까  (2) 2022.06.22
mariaDB json value값만 가져오기  (0) 2021.07.21