🔐 MSSQL 트랜잭션 락 (Locking) 이슈 완벽 정리
✅ 1. 락이란?
**락(Lock)**은 데이터의 정합성과 일관성을 보장하기 위해
SQL Server가 데이터에 대한 접근을 제어하는 메커니즘입니다.
📦 락의 주요 유형
락 종류 | 설명 |
Shared (S) | 읽기 락 (SELECT 시 걸림) |
Exclusive (X) | 쓰기 락 (INSERT, UPDATE, DELETE) |
Update (U) | 업데이트 시 걸리는 임시 락 |
Intent (IS, IX) | 테이블/페이지 단위에 걸리는 의도 락 |
🔥 2. 락이 걸리는 주요 상황
상황 | 설명 |
SELECT + 트랜잭션 | 읽은 데이터가 락 걸려 다른 트랜잭션에서 못 씀 |
UPDATE / DELETE 대기 | 다른 트랜잭션이 아직 COMMIT 안 해서 기다림 |
인덱스 미사용 | 풀스캔 → 더 넓은 범위 락 발생 |
같은 테이블을 동시에 수정 | 레코드 충돌 발생 |
오래 지속되는 트랜잭션 | LOCK 보유 시간 증가 → BLOCKING 확률 증가 |
⚔ 3. "락이 걸리는 현상"의 유형
🟡 Blocking (블로킹)
- 한 트랜잭션이 락을 잡고 있고, 다른 트랜잭션이 기다리는 상태
- 성능 저하, 대기 증가
🔴 Deadlock (교착 상태)
- 서로의 락을 기다리다가 순환 대기가 되어 둘 다 멈추는 상태
- SQL Server가 자동으로 한 쪽 트랜잭션을 강제 종료함
🛡 4. 락 회피 전략 (총망라)
✅ A. 트랜잭션을 짧고 빠르게
- 트랜잭션은 꼭 필요한 최소한의 범위로만 잡기
-- ❌ 안 좋은 예: SELECT 포함
BEGIN TRANSACTION
SELECT * FROM Orders WHERE UserID = @UserID;
UPDATE Orders SET Status = 'C' WHERE OrderID = 1;
COMMIT;
-- ✅ 좋은 예: SELECT는 트랜잭션 밖에서 처리
SELECT * FROM Orders WHERE UserID = @UserID;
BEGIN TRANSACTION
UPDATE Orders SET Status = 'C' WHERE OrderID = 1;
COMMIT;
✅ B. 일관된 접근 순서로 DEADLOCK 회피
- 여러 테이블에 동시에 접근한다면 항상 같은 순서로
-- ❌ 서로 다른 순서로 접근하면 데드락 가능
T1: UPDATE A → UPDATE B
T2: UPDATE B → UPDATE A
-- ✅ 항상 같은 순서
T1, T2: UPDATE A → UPDATE B
✅ C. 적절한 인덱스를 사용해서 락 범위 최소화
- 인덱스 없으면 테이블 전체 스캔 → 넓은 범위 락 발생
- WHERE 조건과 JOIN 조건에 인덱스를 걸어주면 효과적
✅ D. WITH (NOLOCK) 사용 (주의 요망)
SELECT * FROM Orders WITH (NOLOCK);
- S 락을 잡지 않음 → 다른 트랜잭션에 영향을 주지 않음
- 대신 더티 리드 (읽은 값이 COMMIT되지 않았을 수 있음) 위험 존재
- 조회 전용, 중요하지 않은 SELECT에만 사용
✅ E. READ COMMITTED SNAPSHOT 설정 (추천)
- 버전 기반 읽기 기능 → SELECT가 다른 트랜잭션에 의해 블로킹되지 않음
-- 데이터베이스에 설정
ALTER DATABASE [YourDB] SET READ_COMMITTED_SNAPSHOT ON;
- 즉, SELECT는 버전 데이터를 읽고, WRITE는 별도로 진행됨
- SELECT로 인한 락을 근본적으로 회피할 수 있음
✅ F. WAIT 옵션 조정 (SET LOCK_TIMEOUT)
SET LOCK_TIMEOUT 5000; -- 5초 대기 후 오류 반환
- 무한정 기다리지 않고 일정 시간 지나면 오류 반환
- 프로그램에서 리트라이 로직과 함께 쓰면 유용
✅ G. 트랜잭션 격리 수준 변경
수준 | 설명 | 특징 |
READ UNCOMMITTED | NOLOCK과 같음 | 가장 위험, 거의 사용 금지 |
READ COMMITTED (기본) | COMMIT된 데이터만 읽음 | 블로킹 발생 가능 |
SNAPSHOT | 버전 기반 읽기 | RCSI와 유사 |
SERIALIZABLE | 완전 고립 | 락 많이 생김, 피할 것 |
SET TRANSACTION ISOLATION LEVEL SNAPSHOT;
🧪 5. 실시간 락/블로킹 감지 쿼리
현재 블로킹 상태 조회
SELECT
blocking_session_id, session_id, wait_type, wait_time, wait_resource
FROM sys.dm_exec_requests
WHERE blocking_session_id <> 0;
데드락 발생 정보 로그 확인 (XEvent)
-- 데드락 Extended Event 활성화
CREATE EVENT SESSION DeadlockSession
ON SERVER
ADD EVENT sqlserver.deadlock_graph
ADD TARGET package0.ring_buffer
WITH (STARTUP_STATE = ON);
🧠 실무 정리 요약
전략 | 설명 |
트랜잭션 최소화 | SELECT는 바깥, UPDATE만 안에서 |
동일한 테이블 접근 순서 유지 | 데드락 예방 |
인덱스 튜닝 | 락 범위 최소화 |
SNAPSHOT 격리 or RCSI 사용 | 읽기 락 해소 |
SELECT에 NOLOCK 조건부 사용 | 더티 리드 주의 |
LOCK_TIMEOUT 설정 | 블로킹 무한대기 방지 |
정기적인 모니터링 | DM 뷰, XEvent 등 활용 |
📌 결론
트랜잭션 락은 반드시 발생하지만, 잘 설계하면 거의 대부분 예방 또는 완화할 수 있습니다.
중요한 건:
- 최소 트랜잭션 범위
- 일관된 처리 순서
- 데이터베이스 격리 전략
- 읽기/쓰기 분리
입니다.
'프로그래밍 > MSSQL' 카테고리의 다른 글
[MSSQL] 트랜잭션 (Transaction) 실무 고급 주제 3가지 (0) | 2025.03.26 |
---|---|
[MSSQL] Stored Procedure 실무 고급 활용 정리 (0) | 2025.03.26 |
[MSSQL] Stored Procedure 실무 완전정복 (0) | 2025.03.26 |
[MSSQL] 데이터 타입 (Data Type) 완전 정복 (0) | 2025.03.26 |
[MSSQL] DATETIME 포맷 방법 (0) | 2025.03.26 |