적용 대상: SQL Server 2025(17.x)
Azure SQL Database
Azure SQL Managed Instance
Microsoft Fabric의 SQL 데이터베이스
최적화된 잠금은 동시 트랜잭션에 대한 잠금 차단 및 잠금 메모리 사용을 줄이기 위해 향상된 트랜잭션 잠금 메커니즘을 제공합니다.
최적화된 잠금이란 무엇인가요?
최적화된 잠금은 대용량 트랜잭션에 대해서도 잠금이 거의 유지되지 않는 잠금 메모리를 줄이는 데 도움이 됩니다. 또한 최적화된 잠금은 잠금 에스컬레이션을 방지하고 특정 유형의 교착 상태를 방지할 수 있습니다. 따라서 테이블에 대한 더 많은 동시 액세스가 허용됩니다.
최적화된 잠금은 TID(트랜잭션 ID) 잠금 및 LAQ(한정 후 잠금)의 두 가지 기본 구성 요소로 구성됩니다.
- TID(트랜잭션 ID)는 트랜잭션의 고유 식별자입니다. 각 행은 마지막으로 수정한 TID로 레이블이 지정됩니다. 잠재적으로 많은 키 또는 행 식별자 잠금 대신 TID의 단일 잠금을 사용하여 수정된 모든 행을 보호합니다. 자세한 내용은 TID(트랜잭션 ID) 잠금을 참조하세요.
- LAQ(자격 증명 후 잠금)는 잠금을 획득하지 않고 행의 커밋된 최신 버전을 사용하여 쿼리 조건자를 평가하여 동시 실행을 개선하는 최적화 방법입니다. LAQ에는 RCSI(커밋된 읽기 스냅샷 격리)가 필요합니다. 자세한 내용은 LAQ(인증 후 잠금)을 참조하세요.
다음은 그 예입니다.
- 최적화된 잠금이 없으면 테이블에서 1,000개의 행을 업데이트하려면 트랜잭션이 끝날 때까지 1,000개의 배타적(
X) 행 잠금이 필요할 수 있습니다. - 최적화된 잠금을 사용하면 테이블에서 1,000개의 행을 업데이트하려면 1,000
X개의 행 잠금이 필요할 수 있지만 각 잠금은 각 행이 업데이트되는 즉시 해제되고 트랜잭션이 끝날 때까지 하나의XTID 잠금만 유지됩니다. 잠금이 빠르게 해제되므로 잠금 메모리 사용량이 줄어들고 잠금 에스컬레이션 이 발생할 가능성이 훨씬 적어 워크로드 동시 실행이 향상됩니다.
Note
최적화된 잠금을 사용하도록 설정하면 DML(데이터 수정 언어) 문(예: INSERT, UPDATE, DELETE, MERGE)에서 획득한 행 및 페이지 잠금이 감소하거나 제거됩니다. 스키마 잠금과 같은 다른 종류의 데이터베이스 및 개체 잠금에는 영향을 주지 않습니다.
Availability
다음 표에서는 SQL 플랫폼에서 최적화된 잠금의 가용성 및 사용 상태를 요약합니다.
| Platform | Available | 기본 설정으로 활성화됨 |
|---|---|---|
| Azure SQL 데이터베이스 | Yes | 예(항상 사용) |
| Microsoft Fabric의 SQL 데이터베이스 | Yes | 예(항상 사용) |
| Azure SQL Managed InstanceAUTD | Yes | 예(항상 사용) |
| Azure SQL Managed Instance2025 | Yes | 예(항상 사용) |
| Azure SQL Managed Instance2022 | No | N/A |
| SQL Server 2025(17.x) | Yes | 아니요(데이터베이스당 사용하도록 설정할 수 있습니다). |
| SQL Server 2022(16.x) 및 이전 버전 | No | N/A |
사용 및 사용 안 함
SQL Server 데이터베이스에 대해 최적화된 잠금을 사용하거나 사용하지 않도록 설정하려면 이 ALTER DATABASE ... SET OPTIMIZED_LOCKING = ON | OFF 명령을 사용합니다. 자세한 내용은 ALTER DATABASE SET 옵션을 참조하세요.
다른 데이터베이스 기능에 최적화된 잠금 빌드:
- 최적화된 잠금을 사용하도록 설정하려면 먼저 데이터베이스에서 ADR(가속 데이터베이스 복구) 을 사용하도록 설정해야 합니다. 반대로 ADR을 사용하지 않도록 설정하려면 활성화된 경우 먼저 최적화된 잠금을 사용하지 않도록 설정해야 합니다.
- 최적화된 잠금의 이점을 최대한 활용하려면 데이터베이스에 대해 커밋된 RCSI(읽기 커밋된 스냅샷 격리)를 사용하도록 설정해야 합니다. 최적화된 잠금의 LAQ 구성 요소는 RCSI를 사용하는 경우에만 적용됩니다.
ADR은 항상 Microsoft Fabric의 Azure SQL Database, Azure SQL Managed Instance 및 SQL 데이터베이스에서 사용하도록 설정됩니다. RCSI는 기본적으로 Microsoft Fabric의 Azure SQL Database 및 SQL 데이터베이스에서 사용하도록 설정됩니다.
현재 데이터베이스에 대해 이 옵션이 사용하도록 설정되어 있는지 확인하려면 데이터베이스에 연결하여 다음 T-SQL 쿼리를 실행합니다.
SELECT database_id,
name,
is_accelerated_database_recovery_on,
is_read_committed_snapshot_on,
is_optimized_locking_on
FROM sys.databases
WHERE name = DB_NAME();
최적화된 잠금이 사용하도록 설정되어 있나요?
최적화된 잠금은 데이터베이스별로 사용하도록 설정됩니다. 데이터베이스에 연결한 후, 다음 쿼리를 사용하여 최적화된 잠금이 사용하도록 설정되어 있는지 확인합니다.
SELECT DATABASEPROPERTYEX(DB_NAME(), 'IsOptimizedLockingOn') AS is_optimized_locking_enabled;
| Result | Description |
|---|---|
0 |
최적화된 잠금을 사용 안 하도록 설정되어 있습니다. |
1 |
최적화된 잠금을 사용하도록 설정되어 있습니다. |
NULL |
최적화된 잠금을 사용할 수 없습니다. |
sys.databases 카탈로그 뷰를 사용할 수도 있습니다. 예를 들어 모든 데이터베이스에 대해 최적화된 잠금이 사용하도록 설정되어 있는지 확인하려면 다음 쿼리를 실행합니다.
SELECT database_id,
name,
is_optimized_locking_on
FROM sys.databases;
잠금 개요
최적화된 잠금을 사용하도록 설정하지 않은 경우의 동작에 대한 간단한 요약입니다. 자세한 내용은 트랜잭션 잠금 및 행 버전 관리 가이드를 참조하세요.
데이터베이스 엔진에서 잠금은 트랜잭션의 ACID 속성을 보장하기 위해 여러 트랜잭션이 동일한 데이터를 동시에 업데이트하지 못하도록 하는 메커니즘입니다.
트랜잭션이 데이터를 수정해야 하는 경우 데이터에 대한 잠금을 요청합니다. 데이터에 충돌하는 다른 잠금이 없으면 잠금이 부여되고 트랜잭션이 수정 작업을 진행할 수 있습니다. 다른 충돌 잠금이 데이터에 유지되는 경우 트랜잭션은 잠금이 해제될 때까지 기다렸다가 계속 진행해야 합니다.
여러 트랜잭션이 동일한 데이터에 동시에 액세스하려고 할 때 데이터베이스 엔진은 동시 읽기 및 쓰기와 잠재적으로 복잡한 충돌을 해결해야 합니다. 잠금은 엔진이 ANSI SQL 트랜잭션 격리 수준에 대한 의미 체계를 제공할 수 있는 메커니즘 중 하나입니다. 데이터베이스 잠금은 필수이지만 동시성, 교착 상태, 복잡성 및 잠금 오버헤드가 감소하면 성능 및 확장성에 영향을 줄 수 있습니다.
TID(트랜잭션 ID) 잠금
격리 수준 기반의 행 버전 관리가 사용 중일 때 또는 ADR이 사용하도록 설정되어 있을 때 데이터베이스의 모든 행에는 내부적으로 TID(트랜잭션 ID)가 포함됩니다. TID는 행 데이터에 영속적으로 저장됩니다. 행을 수정하는 모든 트랜잭션은 해당 TID를 사용하여 행에 스탬프를 찍습니다.
TID 잠금을 사용하면 행의 키를 잠그는 대신 행의 TID에 대해 잠금이 수행됩니다. 수정 트랜잭션은 해당 TID에 X 잠금을 보유합니다. 다른 트랜잭션은 TID에 대한 S 잠금을 획득하여 첫 번째 트랜잭션이 완료될 때까지 기다립니다. TID 잠금을 사용하면 수정에 대해 페이지 및 행 잠금이 계속 수행되지만, 각 행이 수정되는 즉시 각 페이지 및 행 잠금이 해제됩니다. 트랜잭션이 끝날 때까지 유지되는 유일한 잠금은 TID 리소스에 대한 단일 X 잠금으로, 여러 페이지 및 행(키) 잠금을 대체합니다.
쓰기 트랜잭션이 활성 상태인 동안 현재 세션에 대한 잠금을 보여 주는 다음 예제를 살펴보겠습니다.
/* Is optimized locking is enabled? */
SELECT DATABASEPROPERTYEX(DB_NAME(), 'IsOptimizedLockingOn') AS is_optimized_locking_enabled;
CREATE TABLE t0
(
a int PRIMARY KEY,
b int NULL
);
INSERT INTO t0 VALUES (1,10),(2,20),(3,30);
GO
BEGIN TRANSACTION;
UPDATE t0
SET b = b + 10;
SELECT *
FROM sys.dm_tran_locks
WHERE request_session_id = @@SPID
AND
resource_type IN ('PAGE','RID','KEY','XACT');
COMMIT TRANSACTION;
GO
DROP TABLE IF EXISTS t0;
최적화된 잠금을 사용하는 경우 요청은 X(트랜잭션) 리소스에 대한 단일 XACT 잠금만 보유합니다.
최적화된 잠금을 사용하도록 설정하지 않은 경우 동일한 요청에는 행이 포함된 페이지의 IX(의도 배타적) 잠금 1개와 각 행에 대한 세 개의 X 키 잠금 등 4개의 잠금이 있습니다.
sys.dm_tran_locks DMV(동적 관리 뷰)는 잠금 문제를 검사하거나 해결하는 데 유용합니다. 여기서는 최적화된 잠금 작동을 관찰하는 데 사용됩니다.
자격 후 잠금 (LAQ)
TID 인프라를 기반으로 하는 최적화된 잠금의 LAQ 구성 요소는 DML 문(예: INSERTUPDATEDML 문)을 변경하고 DELETE 잠금을 획득합니다.
최적화된 잠금이 없으면 먼저 업데이트(U) 행 잠금을 수행하여 쿼리 조건자가 행별로 검사됩니다. 조건자가 충족되면 행을 업데이트하기 전에 배타적(X) 행 잠금이 수행되고 트랜잭션 종료까지 유지됩니다.
최적화된 잠금을 READ COMMITTED 사용하고 RCSI(스냅샷 격리 수준)를 사용하도록 설정하면 잠금을 설정하지 않고도 커밋된 최신 버전의 행에서 조건자를 낙관적으로 확인할 수 있습니다. 조건이 충족되지 않으면 쿼리가 스캔의 다음 행으로 이동합니다. 조건자가 충족되면 행을 업데이트하기 위해 X 행 잠금이 수행됩니다.
즉, 잠금은 행을 수정하기 위해 자격 확보 후로 수행됩니다.
X 행 잠금은 트랜잭션이 종료되기 전에 행 업데이트가 완료되는 즉시 해제됩니다.
조건자 평가는 잠금을 획득하지 않고 수행되므로 서로 다른 행을 수정하는 동시 쿼리는 서로를 차단하지 않습니다.
다음은 그 예입니다.
/* Confirm that optimized locking and read committed snapshot isolation (RCSI) are both enabled on this database. */
SELECT database_id,
name,
is_accelerated_database_recovery_on,
is_optimized_locking_on,
is_read_committed_snapshot_on
FROM sys.databases
WHERE name = DB_NAME();
CREATE TABLE t1
(
a int NOT NULL,
b int NULL
);
INSERT INTO t1
VALUES (1,10),(2,20),(3,30);
GO
| 세션 1 | 세션 2 |
|---|---|
BEGIN TRANSACTION;UPDATE t1SET b = b + 10WHERE a = 1; |
|
BEGIN TRANSACTION;UPDATE t1SET b = b + 10WHERE a = 2; |
|
COMMIT TRANSACTION; |
|
COMMIT TRANSACTION; |
최적화된 잠금이 없으면 세션 1이 행 세션 2에 대한 U 잠금을 유지하므로 세션 2가 차단됩니다. 최적화된 잠금을 사용하면 U 잠금이 수행되지 않으며, 커밋된 최신 버전의 행 1에서 열 a이 1과 같아서 세션 2의 조건에 부합하지 않기 때문에, 세션 2는 차단되지 않습니다.
LAQ는 조건자를 확인한 후 행이 수정되지 않는다는 가정 하에 낙관적으로 수행됩니다. 조건자가 충족되고 조건자를 확인한 후 행이 수정되지 않은 경우 현재 트랜잭션에 의해 수정됩니다.
잠금이 U 적용되지 않으므로 조건이 평가된 후 동시 트랜잭션이 행을 수정할 수 있습니다. 행에 TID 잠금을 보유하는 X 활성 트랜잭션이 있는 경우 데이터베이스 엔진이 완료되기를 기다립니다. 이전에 조건자를 평가한 후 행이 변경된 경우 데이터베이스 엔진은 행을 수정하기 전에 조건자를 다시 평가(다시 한도)합니다. 조건자가 여전히 충족되면 행이 수정됩니다.
조건자 재등급은 쿼리 엔진 연산자의 하위 집합에서 지원됩니다. 조건자 다시 평가가 필요하지만 쿼리 계획에서 조건자 재등급을 지원하지 않는 연산자를 사용하는 경우 데이터베이스 엔진은 내부적으로 문 처리를 중단하고 LAQ 없이 다시 시작합니다. 이러한 중단이 발생하면 lock_after_qual_stmt_abort 확장 이벤트가 발생합니다.
일부 문(예 UPDATE : 변수 할당이 있는 문 및 OUTPUT 절이 있는 문)은 의미 체계를 변경하지 않고는 중단 및 다시 시작할 수 없습니다. 이러한 문의 경우 LAQ는 사용되지 않습니다.
다음 예제에서는 다른 트랜잭션이 행을 변경했기 때문에 조건자가 다시 평가됩니다.
CREATE TABLE t3
(
a int NOT NULL,
b int NULL
);
INSERT INTO t3 VALUES (1,10),(2,20),(3,30);
GO
| 세션 1 | 세션 2 |
|---|---|
BEGIN TRANSACTION;UPDATE t3SET b = b + 10WHERE a = 1; |
|
BEGIN TRANSACTION;UPDATE t3SET b = b + 10WHERE a = 1; |
|
COMMIT TRANSACTION; |
|
COMMIT TRANSACTION; |
인덱스 잠금 건너뛰기(SIL)
TID 잠금을 사용하면 짧은 기간 배타적(X) 행 잠금 및 의도 배타적(IX) 페이지 잠금이 행을 수정하는 데 사용됩니다. RCSI 및 LAQ를 사용하는 경우, 이러한 잠금은 다른 쿼리가 행에 액세스하여 안정성을 유지해야 할 경우에만 필요합니다. 이러한 쿼리의 예로는 REPEATABLE READ나 SERIALIZABLE 격리 수준에서 실행되는 쿼리 또는 SERIALIZABLE의 해당 잠금 힌트를 사용하는 쿼리가 있습니다. 이러한 쿼리를 RLQ( 행 잠금 쿼리 )라고 합니다.
행에 액세스하는 RLQ 쿼리가 없는 경우 데이터베이스 엔진은 행을 수정할 때 행 및 페이지 잠금을 사용하지 않고 전용 페이지 래치만 사용할 수 있습니다. 이 최적화는 ACID 트랜잭션 의미 체계를 유지하면서 잠금 오버헤드를 줄입니다. 행 및 페이지 잠금을 건너뛰면 특히 많은 수의 행을 수정하는 트랜잭션에 이점이 있습니다.
현재 SIL 최적화는 다음 경우에만 사용됩니다.
-
INSERT힙에 대한 구문입니다.-
IX페이지 잠금이 건너뛰어집니다.
-
-
UPDATE클러스터형 인덱스, 비클러스터형 인덱스, 힙에 대한 문장입니다.-
IX페이지 잠금 및X행 잠금을 건너뜁습니다.
-
SIL 최적화는 현재 다음 경우에 사용되지 않습니다.
-
DELETE문. -
UPDATE행에 기존 전달 포인터가 포함되어 있거나 업데이트로 새 전달 포인터가 추가되는 경우, 힙에 대한 명령입니다. - 수정된 행에
varchar(max),nvarchar(max),varbinary(max),json와 같은 LOB 데이터 형식을 사용하는 열이 있는 경우 - 동일한 트랜잭션에서 분할된 페이지의 행에 대한 것입니다.
LAQ 휴리스틱
LAQ(한정 후 잠금)에 설명된 대로 LAQ를 사용하는 경우 조건자 재등록을 지원하지 않는 쿼리 연산자를 사용하는 문은 LAQ 없이 내부적으로 다시 시작 및 처리될 수 있습니다. 이런 일이 자주 발생하면 재처리 오버헤드가 클 수 있습니다. 오버헤드를 최소화하기 위해 최적화된 잠금은 오버헤드가 임계값을 초과하는 경우 LAQ를 사용하지 않도록 설정하는 추론 기반 피드백 메커니즘을 사용합니다.
피드백 메커니즘을 위해 문에서 수행하는 작업은 논리적 읽기 수로 측정됩니다. 데이터베이스 엔진이 문 처리가 시작된 후 다른 트랜잭션에 의해 수정된 행을 수정하는 경우 문을 다시 처리해야 할 수 있으므로 문에서 수행한 작업이 잠재적으로 낭비되는 것으로 처리됩니다.
문이 실행될 때 데이터베이스 엔진은 잠재적으로 낭비될 수 있는 작업, 문 재처리 발생 및 재처리될 수 있는 문에 의해 수행된 총 작업을 추적하는 LAQ 피드백 데이터를 유지 관리합니다.
잠재적으로 낭비될 수 있는 작업의 총 작업 비율 또는 총 문 수에 대한 재처리된 문 수의 비율이 해당 임계값을 초과하는 경우 LAQ를 사용할 수 없습니다. 이 두 비율이 임계값 아래로 떨어지면 LAQ를 다시 활성화합니다.
LAQ 피드백 데이터는 다음 두 가지 수준에서 추적됩니다.
쿼리 계획의 경우
- 데이터베이스 엔진은 문장이 재처리되는 것이 처음 발생하면 계획을 위한 LAQ 피드백 추적을 시작합니다.
- 쿼리가 쿼리 저장소에 캡처되면 쿼리 저장소에서도 LAQ 피드백이 캡처됩니다. 데이터베이스 엔진은 이 피드백을 사용하여 데이터베이스가 다시 시작될 경우 계획에 대해 LAQ를 사용하거나 사용하지 않도록 설정합니다.
- 캡처된 LAQ 피드백이 있는 쿼리 계획에는
plan_id카탈로그 뷰에 일치하는 값이 있는 행이 있습니다.feature_id열과feature_desc열은 각각 4와LAQ Feedback로 설정됩니다.
데이터베이스의 경우
- 피드백은 쿼리 계획 수준 피드백이 없는 모든 문(예: 쿼리 저장소에서 쿼리가 캡처되지 않은 경우)에 대해 집계됩니다.
- 피드백은 데이터베이스 시작 이후 추적되며 시작할 때마다 다시 만들어집니다.
문에 LAQ를 사용할지 여부를 결정할 때 시스템은 사용 가능한 경우 쿼리 계획 피드백을 사용합니다. 그렇지 않으면 데이터베이스 수준 피드백을 사용합니다. 즉, 일부 문은 LAQ를 사용하여 실행될 수 있으며 일부는 LAQ 없이 실행될 수 있습니다. 예를 들어 쿼리 계획에 대해 LAQ를 사용하지 않도록 설정할 수 있지만 데이터베이스에 대해 사용하도록 설정하고 그 반대의 경우도 마찬가지입니다.
LAQ 제한 사항
다음 시나리오에서는 자격이 부여된 후 잠금이 사용되지 않습니다.
- LAQ 추론에 의해 비활성화 된 경우.
- 충돌하는 잠금 힌트(예:
UPDLOCK,READCOMMITTEDLOCK또는XLOCKHOLDLOCK사용됨)입니다. - 트랜잭션 격리 수준이
READ COMMITTED이외인 경우 또는READ_COMMITTED_SNAPSHOT데이터베이스 옵션이 사용되지 않도록 설정된 경우입니다. - 수정 중인 테이블에 columnstore 인덱스가 있는 경우
- DML 문에 변수 할당이 포함된 경우
- DML 문에
OUTPUT절이 포함된 경우 - DML 문이 둘 이상의 인덱스 검색 또는 검사 연산자를 사용하여 수정되는 행을 읽는 경우
- In
MERGE문에서.
최적화된 잠금 및 RCSI를 사용하여 쿼리 동작 변경
엄격한 트랜잭션 실행 순서를 사용하는 읽기 커밋된 RCSI(스냅샷 격리)의 동시 워크로드에서 최적화된 잠금을 사용하도록 설정할 때 다른 쿼리 동작의 차이를 경험할 수 있습니다.
트랜잭션 T2가 트랜잭션 T1 중에 업데이트된 t4 열을 기반으로 b 테이블을 업데이트하는 다음 예제를 고려해 보세요.
CREATE TABLE t4
(
a int NOT NULL,
b int NULL
);
INSERT INTO t4
VALUES (1,1);
GO
| 세션 1 | 세션 2 |
|---|---|
BEGIN TRANSACTION T1;UPDATE t4SET b = 2WHERE a = 1; |
|
BEGIN TRANSACTION T2;UPDATE t4SET b = 3WHERE b = 2; |
|
COMMIT TRANSACTION; |
|
COMMIT TRANSACTION; |
한정 후 잠금(LAQ)을 사용했을 때와 사용하지 않았을 때 이전 시나리오의 결과를 평가해 보겠습니다.
LAQ가 없는 경우
LAQ가 없으면 트랜잭션 T2의 UPDATE 문이 차단되고 트랜잭션 T1이 완료될 때까지 기다립니다. T1이 완료되면 T2는 조건자가 충족되므로 행 설정 열 b을 3로 업데이트합니다.
두 트랜잭션이 모두 커밋되면 t4 테이블에 다음 행이 포함됩니다.
a | b
1 | 3
LAQ를 사용하여
LAQ를 사용하면 트랜잭션 T2는 b 열이 1과 같은 행의 커밋된 최신 버전을 사용하여 조건자(b = 2)를 평가합니다. 행이 자격을 갖추지 못하므로 건너뛰고 트랜잭션 T1에 의해 차단되지 않고 명령문이 완료됩니다. 이 예제에서 LAQ는 차단을 제거하지만 결과가 달라집니다.
두 트랜잭션이 모두 커밋되면 t4 테이블에 다음 행이 포함됩니다.
a | b
1 | 2
Important
LAQ가 없더라도 애플리케이션은 행 버전 관리 기반 격리 수준을 사용할 때 잠금 힌트를 사용하지 않고 데이터베이스 엔진이 엄격한 순서를 보장한다고 가정해서는 안 됩니다. 이전 예제와 같이 엄격한 트랜잭션 실행 순서를 사용하는 RCSI 아래의 동시 워크로드에 있는 고객을 위한 일반적인 권장 사항은 와 REPEATABLE READ처럼 SERIALIZABLE하는 것입니다.
최적화된 잠금에 대한 추가 진단 항목
다음 개선 사항은 최적화된 잠금을 사용하는 경우 차단 및 교착 상태를 모니터링하고 문제를 해결하는 데 도움이 됩니다.
- 최적화된 잠금을 위한 대기 유형
-
XACTTID의S잠금에 대한 대기 유형 및 sys.dm_os_wait_stats 리소스 설명:-
LCK_M_S_XACT_READ- 태스크가 읽을 의도로XACTwait_resource형식에 대한 공유 잠금을 대기할 때 발생합니다. -
LCK_M_S_XACT_MODIFY- 태스크가 수정할 의도로XACTwait_resource형식에 대한 공유 잠금을 대기할 때 발생합니다. -
LCK_M_S_XACT- 작업이 의도를 유추할 수 없는XACTwait_resource형식에 대한 공유 잠금을 기다리는 경우에 발생합니다. 이 시나리오는 일반적이지 않습니다.
-
-
- 리소스 잠금 표시 유형
- 리소스 표시 대기
- 교착 상태 그래프
- 교착 상태 보고서
<resource-list>의 각 리소스에서 각<xactlock>요소는 교착 상태의 각 멤버의 잠금에 대한 기본 리소스 및 특정 정보를 보고합니다. 자세한 내용과 예제는 최적화된 잠금 및 교착 상태를 참조하세요.
- 교착 상태 보고서
- 확장 이벤트
- 이
lock_after_qual_stmt_abort이벤트는 다른 트랜잭션과의 충돌로 인해 명령문이 내부적으로 재처리될 때 발생합니다. 자세한 내용은 LAQ(인증 후 잠금)을 참조하세요. - 이
locking_stats이벤트는 몇 분마다 모든 데이터베이스에 대해 발생하며 잠금 에스컬레이션 수, 최적화된 잠금의 TID 잠금 및 LAQ 구성 요소 사용 여부, 다양한 이유로 LAQ가 사용되지 않은 쿼리 수와 같은 시간 간격에 대한 집계 잠금 통계를 제공합니다. 이 이벤트는 최적화된 잠금을 사용하지 않도록 설정된 경우에도 발생합니다. - SQL Server 및 Azure SQL Managed Instance에서
locking_stats2이벤트가 몇 분마다 모든 데이터베이스에 대해 발생하며, 시간 간격에 대한 인덱스 잠금 생략과 LAQ 휴리스틱 통계를 제공합니다.
- 이
최적화된 잠금을 사용하는 모범 사례
RCSI(읽기 커밋된 읽기 스냅샷 격리)를 사용하도록 설정
최적화된 잠금의 이점을 최대화하려면 데이터베이스에서 RCSI(커밋된 읽기 스냅샷 격리) 를 사용하도록 설정하고 격리를 기본 격리 수준으로 사용하는 READ COMMITTED 것이 좋습니다.
Microsoft Fabric의 Azure SQL Database 및 SQL 데이터베이스에서 RCSI는 기본적으로 사용하도록 설정되며 READ COMMITTED 기본 격리 수준입니다. RCSI를 사용하도록 설정하고 READ COMMITTED 격리 수준을 사용하는 경우 reader는 문 시작 시 생성된 스냅샷에서 행의 버전을 읽습니다. LAQ를 사용하면 writer는 U 잠금을 획득하지 않고도 최신 커밋된 행 버전을 기반으로 조건자당 행을 한정합니다. LAQ를 사용하면 행이 조건에 맞고 해당 행에 활성 쓰기 트랜잭션이 있는 경우에만 쿼리가 대기합니다. 커밋된 최신 버전을 기준으로 한정하고 정규화된 행만 잠그면 차단이 줄어들고 동시성이 증가합니다.
힌트 잠금 방지
최적화된 잠금을 사용하도록 설정하면 , UPDLOCK, READCOMMITTEDLOCK, XLOCK 등과 같은 HOLDLOCK가 적용되지만 최적화된 잠금의 이점을 줄일 수 있습니다. 잠금 힌트는 데이터베이스 엔진이 행 또는 페이지 잠금을 가져와 트랜잭션이 끝날 때까지 보관하도록 강제하여 잠금 힌트의 목적을 달성합니다. 일부 애플리케이션에는 잠금 힌트가 필요한 논리가 있습니다(예: UPDLOCK 힌트가 있는 행을 읽은 다음 나중에 업데이트하는 경우). 필요한 경우에만 잠금 힌트를 사용하는 것이 좋습니다.
최적화된 잠금을 사용하면 기존 쿼리에 대한 제한이 없으며 쿼리를 다시 작성할 필요가 없습니다. 힌트를 사용하지 않는 쿼리는 최적화된 잠금을 통해 가장 많은 이점을 얻을 수 있습니다.
쿼리의 한 테이블에 대한 테이블 힌트는 동일한 쿼리에서 다른 테이블의 최적화된 잠금을 방해하지 않습니다. 또한 최적화된 잠금은INSERT, UPDATE, DELETE 또는 MERGE와 같은 DML 문으로 업데이트되는 테이블의 잠금 동작에만 영향을 줍니다. 다음은 그 예입니다.
CREATE TABLE t5
(
a int NOT NULL,
b int NOT NULL
);
CREATE TABLE t6
(
a int NOT NULL,
b int NOT NULL
);
GO
INSERT INTO t5 VALUES (1,10),(2,20),(3,30);
INSERT INTO t6 VALUES (1,10),(2,20),(3,30);
GO
UPDATE t5 SET t5.b = t6.b
FROM t5
INNER JOIN t6 WITH (UPDLOCK)
ON t5.a = t6.a;
이전 쿼리 예제에서는 t6 테이블만 잠금 힌트의 영향을 받지만 t5는 최적화된 잠금의 이점을 활용할 수 있습니다.
UPDATE t5
SET t5.b = t6.b
FROM t5 WITH (REPEATABLEREAD)
INNER JOIN t6
ON t5.a = t6.a;
이전 쿼리 예제에서는 t5 테이블만 REPEATABLE READ 격리 수준을 사용하고 트랜잭션이 끝날 때까지 잠금을 유지합니다.
t5에 대한 다른 업데이트는 최적화된 잠금의 이점을 활용할 수 있습니다.
HOLDLOCK 힌트의 경우도 마찬가지입니다.
질문과 대답(FAQ)
최적화된 잠금은 기본적으로 새 데이터베이스와 기존 데이터베이스 모두에서 활성화되나요?
Azure SQL Database, Azure SQL Managed InstanceAUTD 및 Microsoft Fabric의 SQL 데이터베이스에서는 그렇습니다. SQL Server 2025(17.x)에서 최적화된 잠금은 기본적으로 사용하지 않도록 설정되지만 데이터베이스 복구가 가속화된 모든 사용자 데이터베이스에서 사용하도록 설정할 수 있습니다.
최적화된 잠금이 사용되는지 여부는 어떻게 감지할 수 있나요?
최적화된 잠금이 사용하도록 설정되어 있는지 확인하세요.
최적화된 잠금이 활성화되어 있더라도 쿼리를 강제로 차단하려면 어떻게 해야 하나요?
RCSI가 활성화된 경우, 최적화된 잠금이 활성화된 상태에서 두 쿼리 간의 차단을 강제로 하기 위해 READCOMMITTEDLOCK 테이블 힌트를 사용하세요.
읽기 전용 보조 복제본에서 최적화된 잠금이 사용되나요?
아니요, DML 문은 읽기 전용 복제본에서 실행할 수 없으며 해당 행 및 페이지 잠금은 수행되지 않기 때문입니다.
tempdb 및 임시 테이블에서 데이터를 수정할 때 최적화된 잠금이 사용되나요?
현재는 불가능합니다.