UPDLOCK으로 인해 SELECT가 중단되는 이유는 무엇입니까?


13

SQL SERVER에서 전체 테이블을 잠그는 선택이 있습니다.

설정 스크립트는 다음과 같습니다 (아무것도 덮어 쓰지 않도록하십시오)

USE [master]
GO

IF EXISTS(SELECT 1 FROM sys.databases d WHERE d.name = 'LockingTestDB')
DROP DATABASE LockingTestDB
GO

CREATE DATABASE LockingTestDB
GO

USE [LockingTestDB]
GO
IF EXISTS(SELECT 1 FROM sys.tables t WHERE t.name = 'LockingTestTable')
  DROP TABLE LockingTestTable
GO

CREATE TABLE LockingTestTable (
  Id int IDENTITY(1, 1),
  Name varchar(100),
  PRIMARY KEY CLUSTERED (Id)
)
GO

INSERT INTO LockingTestTable(Name) VALUES ('1')
INSERT INTO LockingTestTable(Name) VALUES ('2')
GO

새 쿼리 창을 열고 대기중인 다음 트랜잭션을 실행하십시오.

USE [LockingTestDB]
GO

BEGIN TRANSACTION
  SELECT * FROM LockingTestTable t WITH (UPDLOCK, ROWLOCK) WHERE t.Name = '1'
  WAITFOR DELAY '00:01:00'

COMMIT TRANSACTION
--ROLLBACK
GO

USE [master]
GO

그리고 다른 하나가 실행될 것입니다 (동시에 실행하십시오).

USE [LockingTestDB]
GO

SELECT * FROM LockingTestTable t WITH (UPDLOCK, ROWLOCK) WHERE t.Name = '2'

USE [master]
GO

두 번째 쿼리는 첫 번째 쿼리에 의해 차단됩니다. 첫 번째 쿼리를 중지하고 ROLLBACK을 실행하면 두 번째 쿼리가 완료됩니다.

왜 이런 일이 발생합니까?

추신 : Name에 클러스터되지 않은 인덱스 (전체 범위 포함)를 추가하면 수정됩니다.

USE [LockingTestDB]
GO

CREATE NONCLUSTERED INDEX [IX_Name] ON [dbo].[LockingTestTable] 
(
  [Name] ASC
)
INCLUDE ( [Id]) WITH (STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO

또 왜?

답변:


19

으로 온라인 설명서 , UPDLOCK업데이트 잠금을 취하고 트랜잭션의 끝을 보유하고 있습니다.

잠글 행을 찾기위한 색인이 없으면 테스트 된 모든 행이 잠기고 규정 된 행의 잠금은 트랜잭션이 완료 될 때까지 유지됩니다.

첫 번째 트랜잭션은 name = 1 인 행에서 업데이트 잠금을 보유합니다. 두 번째 트랜잭션은 동일한 행에서 업데이트 잠금을 획득하려고 시도 할 때 차단됩니다 (해당 행의 name = 2인지 테스트).

인덱스를 사용하면 SQL Server는 적합한 행만 빠르게 찾아서 잠글 수 있으므로 충돌이 없습니다.

잠금 힌트의 이유를 검증하고 적절한 색인이 있는지 확인하려면 자격을 갖춘 데이터베이스 전문가와 코드를 검토해야합니다.

관련 정보 : 읽기 커밋 된 스냅 샷 격리에서 데이터 수정

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.