본문 바로가기

SQL Server/SQL Server Tip & Tech

계륵 같은 SNAPSHOT 격리 수준 - SET TRANSACTION ISOLATION LEVEL SNAPSHOT

SNAPSHOT 격리 수준에서는 행 버전이 관리되기 때문에 Lock을 걸지 않고도 commit된 버전의 행을 읽어 올 수 있습니다.

읽은 데이터의 일관성을 유지 할 수 있을 뿐더러... 읽기 작업에 Lock이 사용되지 않기 때문에 동시성이 좋아집니다.

하지만 행 버전을 관리하기 위한 오버헤드 (tempdb 사용, 데이터에 행 버전 정보 추가 등)도 무시할 순 없습니다.

결국 데이터베이스의 사용 패턴에 따라 선택해줘야 할 사항이 하나 늘었달까요? ^^


SNAPSHOT 격리 수준을 사용하려면 아래와 같이 데이터베이스를 세팅 해 주어야 합니다.

ALTER DATABASE <데이터베이스 이름> SET ALLOW_SNAPSHOT_ISOLATION ON;


재미있는 것은 기존의 READ COMMITTED 격리 수준에서도 Lock 대신 행 버전 정보를 사용 할 수 있도록 설정할 수 있다는 점인데... 아래와 같이 설정해 주면 됩니다. (단, 해당 데이터베이스 컨텍스에 연결되어 있는 다른 접속이 없어야 합니다.)

ALTER DATABASE <데이터베이스 이름> SET READ_COMMITTED_SNAPSHOT ON;


본래 READ COMMITTED 격리 수준에서 읽기 작업을 하면 Shared Lock이 걸리는데, READ_COMMITTED_SNAPSHOT 옵션을 사용하면 Lock을 걸지 않고 행 버전을 통해 commit된 버전을 가져 옵니다.
(이 옵션이 활성화 된 상태에서 SELECT 시 Shared Lock을 걸고 싶다면, WITH (READCOMMITTEDLOCK) 힌트를 사용)

만약 레거시 시스템에 작성되어 있는 SQL문이... READ UNCOMMITTED 격리 수준을 사용하지도 않고, WITH (NOLOCK) 이나 WITH (READUNCOMMITTED)와 같은 힌트도 사용하지 않고 있어 고민이라면... 이 옵션을 사용해 볼 만 합니다.



참고로... READ_COMMITTED_SNAPSHOT 옵션이 ALLOW_SNAPSHOT_ISOLATION 옵션을 사용하는 것 보다 행 버전 관리에 필요한 리소스가 더 적습니다.

이유는 전자는 문 수준에서 행 버전의 일관성이 유지되고, 후자는 트랜잭션 수준에서 유지 되기 때문인데... 자세한 내용은 BOL을 참고하시면 되겠습니다. ^^;



새로 진행하는 프로젝트에 사용해 볼까 생각했는데... 이번 프로젝트에는 적합해 보이지 않는구요.

예전 방식대로 WITH (NOLOCK)을 열심히 써 줘야겠습니다.

SNAPSHOT은... 다음에 빌링 시스템 같은 프로젝트가 있을 때... 그 때 써봐야겠습니다.