[데이터베이스] ACID
ACID
- ACID는 데이터베이스 트랜잭션의 신뢰성을 보장하기 위한 네 가지 주요 속성을 말한다.
- 원자성(Atomicity), 일관성(Consistency), 고립성(Isolation), 지속성(Durability)을 의미한다.
1. 원자성 (Atomicity)
- 트랜잭션은 모두 성공적으로 완료되거나 전혀 실행되지 않은 것처럼 보장되어야 한다.
즉, 트랜잭션의 모든 작업이 완료되거나, 하나라도 실패하면 모든 작업이 취소되어야 한다.
- 예제: 은행 계좌 간 송금
- 트랜잭션: 계좌 A에서 B로 100원을 이체
- 만약 계좌 A에서 100원이 출금된 후, 계좌 B에 입금하는 과정에서 오류가 발생하면, 트랜잭션 전 계좌 A의 100원이 출금되지 않은 상태로 복구되어야 한다.
2. 일관성 (Consistency)
- 트랜잭션 전후 데이터베이스가 항상 일관된 상태를 유지해야 한다.
- 데이터베이스가 데이터 무결성 제약 조건과 비즈니스 규칙을 항상 만족하는 상태를 유지하도록 보장한다.
쉽게 말하자면, 데이터베이스가 유효한, 문제가 없는 상태를 유지해야 한다는 것이다.
- 예제: 외래 키 제약 조건
- 트랜잭션: 자식 테이블에 레코드를 삽입할 때, 참조하는 부모 테이블에 해당 키가 존재해야 한다.
3. 고립성 (Isolation)
- 동시에 여러 트랜잭션이 실행될 때, 각 트랜잭션은 독립적으로 실행된 것처럼 보여야 한다.
하나의 트랜잭션이 완료되기 전에 다른 트랜잭션이 그 결과를 참조하거나 변경하지 못하게 한다.
- 예제: 두 개의 트랜잭션이 동일한 데이터를 읽고 수정
- 트랜잭션 A: 데이터 X를 100에서 200으로 수정
- 트랜잭션 B: 데이터 X를 100에서 300으로 수정
- 트랜잭션 A가 완료되기 전까지 트랜잭션 B는 데이터 X를 읽거나 수정하지 못하게 해야 한다.
4. 지속성 (Durability)
- 트랜잭션이 성공적으로 완료되면, 그 결과는 영구적으로 반영되어야 한다.
시스템 오류가 발생하더라도 데이터베이스에 저장된 데이터는 손실되지 않는다.
- 예제: 데이터베이스 커밋
- 트랜잭션: 주문 정보 저장
- 커밋 후 시스템에 장애가 발생해도 주문 정보는 데이터베이스에 영구적으로 저장되어 있어야 한다.
트랜잭션의 격리 레벨(Isolation Level)
트랜잭션의 격리 레벨은 여러 트랜잭션이 동시에 실행될 때, 각 트랜잭션이 다른 트랜잭션의 중간 상태를 볼 수 있는지를 결정하는 기준으로, 이를 통해 데이터 일관성을 유지하고 동시에 여러 트랜잭션이 처리될 때 발생할 수 있는 문제를 방지한다. SQL 표준은 다음 네 가지 격리 수준을 정의한다.
트랜잭션 격리 수준에서 발생할 수 있는 문제들
- 더티 리드 (Dirty Read): 다른 트랜잭션이 아직 커밋되지 않은 데이터를 읽는 것
- 비반복적 읽기 (Non-repeatable Read): 한 트랜잭션이 같은 데이터를 두 번 읽었을 때, 그 사이에 다른 트랜잭션이 데이터를 변경하여 두 번의 읽기 결과가 다른 것
- 팬텀 리드 (Phantom Read): 한 트랜잭션이 범위 쿼리를 두 번 실행했을 때, 그 사이에 다른 트랜잭션이 데이터를 삽입하거나 삭제하여 두 번의 쿼리 결과가 다른 것
1. Read Uncommitted
- 가장 낮은 격리 수준
다른 트랜잭션이 아직 커밋되지 않은 데이터를 읽을 수 있는데, 이를 “더티 리드”라고 한다.
- 문제점: 더티 리드, 비반복적 읽기, 팬텀 리드 발생 가능
사용 예시: 높은 성능이 필요하지만 데이터 일관성이 덜 중요한 경우
1
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
2. Read Committed
- 기본적인 격리 수준
다른 트랜잭션이 커밋한 데이터만 읽을 수 있으며 더티 리드는 발생하지 않는다.
- 문제점: 비반복적 읽기, 팬텀 리드 발생 가능
사용 예시: 대부분의 데이터베이스 시스템에서 기본 설정으로 사용
1
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
3. Repeatable Read
- 트랜잭션이 시작된 시점부터 커밋될 때까지 다른 트랜잭션이 데이터를 수정할 수 없다.
동일한 트랜잭션 내에서 동일한 데이터를 읽으면 항상 같은 결과를 반환한다.
- 문제점: 팬텀 리드 발생 가능
사용 예시: 은행 시스템 등 데이터 정확성이 중요한 경우
1
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
4. Serializable
- 가장 높은 격리 수준
- 트랜잭션을 직렬화하여 동시에 실행되는 다른 트랜잭션이 서로 간섭하지 않도록 한다.
팬텀 리드, 비반복적 읽기, 더티 리드를 모두 방지한다.
- 문제점: 성능 저하, 병목 현상 발생 가능
사용 예시: 데이터 일관성이 가장 중요한 시스템
1
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
격리 수준과 일관성 및 성능의 균형
- 낮은 격리 수준은 성능이 좋지만 데이터 일관성 문제를 일으킬 수 있다.
높은 격리 수준은 데이터 일관성을 보장하지만 성능이 저하될 수 있다.
- 성능이 좋다는 것은 트랜잭션 처리 속도가 빠르다는 것을 의미한다.
- 트랜잭션 격리 수준이 낮을수록 트랜잭션 간의 상호작용과 데이터 접근이 자유로워져, 데이터베이스 시스템이 더 많은 트랜잭션을 더 빨리 처리할 수 있다.
낮은 격리 수준의 성능 향상 이유
- 락(Lock)의 사용 감소: 낮은 격리 수준에서는 데이터의 읽기/쓰기 시 락을 덜 사용하거나 짧은 시간 동안만 사용한다. 예를 들어,
Read Uncommitted
에서는 더티 리드를 허용하므로 데이터 읽기에 대한 락을 거의 사용하지 않는다. - 동시성 증가: 트랜잭션들이 데이터베이스의 동일한 부분에 동시에 접근할 수 있는 가능성이 높아진다. 이는 동시에 더 많은 트랜잭션을 처리할 수 있게 해준다.
- 트랜잭션 대기 시간 감소: 낮은 격리 수준에서는 트랜잭션들이 데이터 락을 기다리는 시간이 줄어들어, 전체적인 대기 시간이 감소한다.
높은 격리 수준의 성능 저하 이유
- 락(Lock)의 사용 증가: 높은 격리 수준에서는 데이터의 일관성을 보장하기 위해 더 많은 락을 사용한다. 예를 들어,
Serializable
에서는 트랜잭션 간의 상호 간섭을 피하기 위해 모든 관련 데이터를 락을 걸어야 할 수 있다. - 동시성 감소: 트랜잭션들이 데이터베이스의 동일한 부분에 동시에 접근하는 것이 제한된다. 이는 동시 처리할 수 있는 트랜잭션의 수를 줄인다.
- 트랜잭션 대기 시간 증가: 높은 격리 수준에서는 트랜잭션들이 필요한 락을 얻기 위해 기다려야 할 가능성이 높아져, 대기 시간이 증가한다.
성능과 일관성의 균형
격리 수준 | 데이터 일관성 | 성능 (처리 속도) |
---|---|---|
Read Uncommitted | 낮음 | 매우 높음 |
Read Committed | 보통 | 높음 |
Repeatable Read | 높음 | 보통 |
Serializable | 매우 높음 | 낮음 |
정리
- Read Uncommitted: 성능이 가장 좋지만 데이터 일관성은 가장 낮다.
- Read Committed: 대부분의 데이터베이스에서 기본값으로 사용되는 격리 수준으로, 적절한 성능과 데이터 일관성을 제공한다.
- Repeatable Read: 데이터 일관성이 더 중요할 때 사용하며, 팬텀 리드를 제외한 대부분의 일관성 문제를 방지한다.
- Serializable: 가장 높은 데이터 일관성을 제공하지만 성능은 가장 낮다.
성능이 중요하고 일관성 문제를 감수할 수 있는 경우 낮은 격리 수준을 선택할 수 있고, 데이터 일관성이 최우선인 경우 높은 격리 수준을 선택해야 한다.