[Database] 데이터베이스 락(Lock)의 종류와 역할

bluewhale·2022년 1월 21일
1

Database

목록 보기
5/5

락(Lock)이란?

데이터베이스는 여러 사용자들이 같은 데이터를 동시에 접근하는 상황에서, 데이터의 무결성과 일관성을 지키기 위해 락을 사용합니다.

Lock의 종류

데이터베이스의 락은 크게 다음과 같은 종류로 분류할 수 있습니다.

공유 락(Shared Lock)

공유 락은 데이터를 변경하지 않는 읽기 명령에 대해 주어지는 락으로 Read Lock이라고도 불리며 Shared의 앞 글자를 따서 주로 S로 표기합니다. 여러 사용자가 동시에 데이터를 읽어도 데이터의 일관성에는 아무런 영향을 주지 않기 때문에, 공유 락끼리는 동시에 접근이 가능합니다.

베타 락(Exclusive Lock)

베타 락은 데이터에 변경을 가하는 쓰기 명령들에 대해 주어지는 락으로 Write Lock으로도 불리며, X로 표기합니다. 베타 락은 이름처럼 다른 세션이 해당 자원에 접근(ex, SELECT, INSERT..) 하는 것을 막습니다. 이러한 점에서 베타 락은 멀티 쓰레딩 환경에서, 임계 영역을 안전하게 관리하기 위해 활용되는 뮤텍스와 유사하다고 볼 수 있습니다. 베타 락은 트랜잭션 동안 유지됩니다.

업데이트 락(Update Lock)

업데이트 락은 데이터를 수정하기 위해 베타 락(X)을 걸기 전, 데드 락을 방지하기 위해 사용되는 락입니다. 일반적으로 업데이트 락은 UPDATE 쿼리의 필터(WHERE)가 실행되는 과정에서 적용됩니다.

서로 다른 트랜잭션에서 동일한 자원에 대해 읽기 쿼리 이후, 업데이트 쿼리를 적용하는 경우 컨버젼 데드락이 발생하는데, 이를 막기 위해 일부 SELECT 퀴리에서도 업데이트 락을 적용(WITH(UPDLOCK))하기도 합니다.

내재 락(Intent Lock)

내재 락은 앞서 소개한 락들과 사뭇 다른 기능을 합니다. 내재 락은 사용자가 요청한 범위에 대한 락(ex, 테이블 락)을 걸 수 있는지 여부를 빠르게 파악하기 위해 사용되는 락입니다. 내재 락은 공유 락과 베타 락 앞에 I 기호를 붙인 IS, IX, SIX 등이 있습니다.

사용자 A가 테이블의 하나의 로우(row)에 대해 베타 락(X)을 건 경우, 사용자 B가 테이블 전체에 대한 락을 걸기 위해서는(ex, 스키마 변경) 사용자 A의 트랜잭션이 끝날 때까지 기다려야 합니다. 그러나, 사용자 B가 테이블에 락(DDL Lock)을 걸 수 있는지 여부를 파악하기 위해 테이블에 존재하는 모든 로우와 관련된 락을 찾아보는 것은 매우 비효율적인 작업입니다.

따라서, 데이터베이스는 사용자 A가 로우에 베타 락(X)을 거는 시점에, 해당 로우의 상위 객체들(ex, 페이지, 테이블)에 대한 내재 락(IX)을 걸어, 다른 사용자가 더 큰 범위의 자원들에 대해 락을 걸 수 있는지 여부를 빠르게 파악할 수 있도록 돕습니다.

출처: Why do we need Intent Locks in SQL Server?

Lock Escalation

하나의 로우에 대해 락을 생성하면, 상위 객체들에 대한 내재 락들이 함께 생성됩니다. 그러나, 락은 많은 메모리 자원을 필요로 합니다. 따라서, 많은 데이터베이스들은 테이블 내의 일정 비율 이상의 로우에 대한 락을 생성할 경우, 모든 로우에 대해 락을 생성하는 대신, 더 상위 객체인 테이블에만 락을 걸도록하여 메모리 사용을 최적화하는 기능을 지원합니다. 이러한 데이터베이스의 기능을 Lock Escalation이라고 합니다.

Lock의 호환성과 Conversion Deadlock

내제 공유 락(IS)는 배타 락을 제외한 모든 락과 함께 실행이 가능하며, 베타 락은 이름 그대로 다른 락과 호환이 불가능하며, 다른 트랜잭션의 모든 락이 해제될 때까지 실행될 수 없습니다. 동일하게, 베타 락을 얻은 트랜잭션이 커밋/롤백 할 때까지 동일 범위에 대한 모든 락은 실행 권한을 얻을 수 없습니다.

운영 단계에서 종종 발생하는 컨버젼 데드락(Conversion Deadlock)은 다른 공유(S)락과 업데이트 락(U)이 동일한 자원에 접근하는 것을 허용하는 공유 락(S)의 성질에서 기인합니다. 데이터베이스는 업데이트(UPDATE ... SET ... WHERE...)를 실행할 때에, 먼저 해당 자원에 대한 공유 락(S)을 얻어온 후 이를 베타 락(X)으로 전환하게 됩니다. 이러한 업데이트 쿼리가 동시에 실행되어 두 트랜잭션이 모두 공유 락(S)을 얻은 후 이를 베타 락(X)으로 전환하려 할때, 상대 트랜잭션이 소유하고 있는 공유 락(S)으로 인해 모든 트랜잭션이 베타 락(X)을 얻지 못 해 업데이트에 실패하게 됩니다.

profile
안녕하세요

4개의 댓글

comment-user-thumbnail
2022년 8월 17일

잘읽었습니다!

1개의 답글
comment-user-thumbnail
2024년 5월 16일

정확히 제게 필요한 정보였습니다. 깔끔한 정리 감사합니다!

1개의 답글