실제 운영중인 시스템에서, 데이터베이스에 의도하지 않은 값이 들어가거나, 중간에 엉뚱한 Insert 또는 Update 쿼리로 인해 데드락이 발생하는 경우가 있었다.(심지어 Select 임에도 불구하고...)
왜 Select중에 교착상태가 발생하는 것일까...? 의문을 가지게 되면서 데이터베이스의 격리수준에 대해 공부하게 되었다.
데이터베이스의 격리 수준은 대표적으로 4가지로 나뉘어진다.(아래로 갈수록 격리 수준 ↑, 성능 ↓)
1. READ UNCOMMITTED
2. READ COMMITTED
3. REPEATABLE READ
4. SERIALIZABLE
하나씩 살펴보자면
1. READ UNCOMMITTED
- Commit 되지 않은 데이터를 읽을 수 있다. 즉 하나의 트랜잭션에서 Insert나 Update 할 경우 Commit이 되지 않아도, 다른 트랜잭션에서 변경된 데이터를 읽을 수 있다는 의미이다.
2. READ COMMITTED
- Commit 된 데이터만 읽을 수 있다. READ COMMITTED 에서는 Row가 Insert나 Update 상태라면, Select는 앞서 수행중인 트랙잭션이 Commit 될때까지 대기상태에 머무르게 된다. 물론 이 경우에도 다른 Row는 가져오는데에 문제가 없다.
- Oracle의 default 설정
3. REPEATABLE READ
- 반복읽기. 한 트랜잭션 내에서 읽었던 값은 변하지 않아야 한다. 즉, 트랜잭션 내에서 읽은 값은 다른 트랙잭션에서 변경조차 불가능하다는 것이다. 한 트랜잭션에서 Select 하게되면 S Lock이 걸리게 되고, 이 상태에서는 같은 S Lock을 공유하는 Select는 가능하나, Update나 Insert는 불가능하다.
- 다만 이 경우에도 다른 Row는 잠기지 않으므로, Insert나 Update가 가능하다.
- MySQL의 default 설정
4. SERIALIZABLE
- 직렬화. 해당 격리수준은 인덱스와도 연관을 가진다. 인덱스가 있는 테이블일 경우 Select중인 Row뿐만 아니라 이전 행과 다음 행까지 잠그게 된다.
- 물론 범위로 Select하게 될 경우에도 해당 범위의 이전행과 다음행까지 잠근다.
- 하지만 SERIALIZABLE 에서 테이블에 인덱스가 없다면, 범위를 특정지을 수 없기 때문에 전 범위에 대한 잠금이 걸리게 된다.
- SERIALIZABLE 격리수준은 가장 강력한 격리수준이지만, 성능저하가 발생할 수 있다.
*각 격리수준에 따라 파생되는 문제에 대해서는 다음 포스팅에 이어서 진행 예정...
더 자세한 설명과 예시는 아래를 참고할 것!
'개발 > DB' 카테고리의 다른 글
[DB] 인덱스를 내 의도대로 설정하자 (0) | 2024.01.07 |
---|---|
[DB] 사용자에 따라 다른 Timezone 결과 조회하기(MariaDB) (0) | 2023.11.19 |
[DB] Entity에 catalog 옵션이 있을 경우 (0) | 2023.03.18 |
[MySQL] 내가 원하는 순서대로 Order by 조건을 주자 (0) | 2023.03.01 |