SELECT… WITH XLOCK을 사용해야하는 이유는 무엇입니까?


11

다시 발생하는 교착 상태에 직면하고 있습니다. 그 중 하나는 Keylock이며 Xlock 힌트가있는 교착 상태 피해자가되는 SELECT 쿼리가 포함되어 있습니다. 다른 명령문은 첫 번째 조회보기의 일부인 테이블 중 하나에 대한 INSERT입니다.

전망:

create view dbo.viewE
 as
    select * from dbo.E  
    where myValue > 13000 

쿼리를 선택하십시오.

select * from dbo.viewE with (XLOCK) where A > GETUTCDATE() 

INSERT 문 :

INSERT INTO [dbo].[E] (myValue,A) VALUES (10,GetDate())

기본 테이블 dbo.E는 약 20 개의 열에 약 3 백만 개의 행을 보유하고 있으며 그 중 일부는 ntext입니다.

두 개의 트랜잭션으로 쿼리를 꺼내 수동으로 시뮬레이트하면 동작을 재현 할 수 있습니다. 선택에서 XLOCK을 제거하면 동작이 변경됩니다.

교착 상태 그래프 :

<deadlock-list>
 <deadlock victim="process222222221">
  <process-list>
   <process id="process222222221" taskpriority="0" logused="0" waitresource="KEY: 5:72057604035644444 (ccdf51accc0c)" waittime="2522" ownerId="27202256401" transactionname="SELECT" lasttranstarted="2015-09-14T16:32:36.160" XDES="0x2f1ec5ca0" lockMode="RangeX-X" schedulerid="15" kpid="12936" status="suspended" spid="359" sbid="0" ecid="0" priority="0" trancount="0" lastbatchstarted="2015-09-14T16:32:36.160" lastbatchcompleted="2015-09-14T16:32:36.160" clientapp="x" hostname="x" hostpid="14536" loginname="x" isolationlevel="serializable (4)" xactid="27202256401" currentdb="5" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
    <executionStack>
     <frame procname="adhoc" line="1" stmtstart="48" sqlhandle="0x02000000611e4523142b2318c47c87313a9b2ba587ff3130">
        SELECT * FROM viewE WITH (XLOCK) WHERE A &lt; GetUtcDate()      </frame>
     <frame procname="unknown" line="1" sqlhandle="0x000000000000000000000000000000000000000000000000">
unknown     </frame>
    </executionStack>
    <inputbuf>
(@UICulture nvarchar(5))SELECT * FROM viewE WITH (XLOCK) WHERE A &lt; GetUtcDate()    </inputbuf>
   </process>
   <process id="process6022222" taskpriority="0" logused="161152" waitresource="KEY: 5:72057604035644444 (cd874c2ba438)" waittime="1370" ownerId="27202248438" transactionguid="0x8de5ccd6eeef67469c6234af59e44ca5" transactionname="DTCXact" lasttranstarted="2015-09-14T16:32:34.767" XDES="0x4aa0bf950" lockMode="RangeI-N" schedulerid="14" kpid="6636" status="suspended" spid="329" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2015-09-14T16:32:37.300" lastbatchcompleted="2015-09-14T16:32:37.300" clientapp="x" hostname="x" hostpid="14536" loginname="x" isolationlevel="read uncommitted (1)" xactid="27202248438" currentdb="5" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
    <executionStack>
     <frame procname="adhoc" line="1" stmtstart="936" sqlhandle="0x020000004853462f09790a4ddedc0d574c2afa539aef1c0e">
     INSERT INTO [E] ([a], [b], [c],...) VALUES (@aDate, @bDate, @c, ...)
     </frame>
     <frame procname="unknown" line="1" sqlhandle="0x000000000000000000000000000000000000000000000000">
unknown     </frame>
    </executionStack>
    <inputbuf>INSERT INTO [E] ([a], [b], [c],...) VALUES (@aDate, @bDate, @c, ...)
    </inputbuf>
   </process>
  </process-list>
  <resource-list>
   <keylock hobtid="72057604035644444" dbid="5" objectname="db.dbo.E" indexname="IX_index1" id="lock258b6dc80" mode="X" associatedObjectId="72057604035644444">
    <owner-list>
     <owner id="process6022222" mode="X"/>
    </owner-list>
    <waiter-list>
     <waiter id="process222222221" mode="RangeX-X" requestType="wait"/>
    </waiter-list>
   </keylock>
   <keylock hobtid="72057604035644444" dbid="5" objectname="db.dbo.E" indexname="IX_index1" id="lock7b145c400" mode="RangeX-X" associatedObjectId="72057604035644444">
    <owner-list>
     <owner id="process222222221" mode="RangeX-X"/>
    </owner-list>
    <waiter-list>
     <waiter id="process6022222" mode="RangeI-N" requestType="wait"/>
    </waiter-list>
   </keylock>
  </resource-list>
 </deadlock>
</deadlock-list>

나는 이것을 이해하는 한 기본적으로 필요한 값을 수집하기 위해 클러스터되지 않은 클러스터 된 인덱스를 사용하는 발견되지 않은 인덱스 쿼리로 인해 발생하는 KEYLOCK 교착 상태를보고 있습니다.

내 질문 :

  1. 필요한 NTEXT 열이 포함되어 포함 인덱스를 만들 수 없습니다. 행 수를 대폭 줄이면 여기에 도움이됩니까?
  2. SELECT가 XLOCK으로 실행되는지 모르는 좋은 이유가 있습니까? XLOCK없이 교착 상태가 발생합니까?

답변:


15

나는 이것을 이해하는 한 기본적으로 필요한 값을 수집하기 위해 클러스터되지 않은 클러스터 된 인덱스를 사용하는 발견되지 않은 인덱스 쿼리로 인해 발생하는 KEYLOCK 교착 상태를보고 있습니다.

본질적으로 그렇습니다. 읽기 작업 (선택)은 먼저 비 클러스터형 인덱스에 액세스 한 다음 클러스터형 인덱스 (조회)에 액세스합니다. 쓰기 작업 (삽입)은 먼저 클러스터형 인덱스에 액세스 한 다음 비 클러스터형 인덱스에 액세스합니다. 호환되지 않는 잠금을 보유한 다른 순서로 동일한 자원에 액세스하면 교착 상태가 발생할 수 있습니다.

행 수를 대폭 줄이면 여기에 도움이됩니까?

그것은 수도 적은 리소스가 잠겨 있기 때문에 작업이 더 빨리 완료하는 경향이있다. 도움이된다면 교착 상태를 줄일 수 있지만 대부분 교착 상태를 제거하지는 않습니다 (그러나 계속 읽으십시오).

SELECT가 XLOCK으로 실행되는지 모르는 좋은 이유가 있습니까?

실제로는 아닙니다. 이와 같은 잠금 힌트는 종종 격리, 잠금 및 교착 상태가 어떻게 작동하는지에 대한 완전한 이해없이 문제를 줄이거 나 제거하려는 필사적 인 시도로 사람들이 소개합니다.

XLOCK없이 교착 상태가 발생합니까?

호환되지 않는 잠금이 다른 순서로 수행되지 않기 때문에 선택이 실제로 커밋되지 않은 읽기 에서 실행되는 경우 아니요 .

, 잠금 격리 수준이 사용되고 호환되지 않는 잠금이 일치하지 않는 순서 (예 : 비 클러스터의 공유 (S), 읽은 경우 클러스터의 S)로 유지되는 경우 이 시나리오에서 교착 상태가 발생할 가능성은 잠금 수와 보유 기간에 따라 다릅니다.

조언

실제로 검토에서 눈에 띄는 것은 선택 트랜잭션이 직렬화 가능한 격리에서 실행되고 있다는 것 입니다. 프레임 워크 또는 DTC (Distributed Transaction Coordinator) 사용으로 인해 설정 될 수 있습니다. 교착 상태 그래프에서 transactionname = "DTCXact"를 참조하십시오. 이에 대한 이유를 조사하고 가능하면 변경해야합니다.

이러한 직렬화가 직렬화 가능하지 않으면 XLOCK힌트가 제거 되었다고 가정 할 때이 교착 상태가 발생하지 않을 가능성이 매우 높습니다 . 즉, 커밋되지 않은 읽기 격리 상태 에서 읽을 것이므로 일관성이 거의 보장되지 않습니다.

응용 프로그램과 SQL Server 코드가 읽기 버전의 행을 허용 할 수있는 경우 읽기에 대해 커밋 된 스냅 샷 격리 (RCSI) 또는 스냅 샷 격리 (SI) 로 변경 하면 교착 상태 ( XLOCK제거됨!)를 피하면서 일관성있는 특정 지점을 제시 할 수 있습니다. 커밋 된 데이터의 시간보기 이것은 물론 직렬화 가능한 격리를 피할 수 있다고 가정합니다.

궁극적으로 XLOCK힌트 비생산적이지만 직렬화 가능한 격리 수준을 사용해야하는 이유를 조사해야합니다. 는 trancount = 2또한 재미있다 - 아마도 당신이 실수로 중첩 트랜잭션이 여기에 있습니다. 확인해야 할 것이 있습니다.


2
  1. 행 수를 대폭 줄이면 교착 상태가 발생할 가능성은 줄어들지 만 완전히 사라지지는 않습니다.

간단히 말해서 선택은 먼저 색인을 사용하여 선택할 행을 결정한 다음 행을 페치하고 삽입은 행을 삽입 한 다음 (XLOCKED) 인덱스를 갱신하려고합니다.

  1. 동일한 트랜잭션에서 나중에 데이터를 업데이트하려는 경우 애플리케이션 개발자는 XLOCK을 사용하는 경향이 있습니다. 따라서 아무도 그 아래의 데이터를 업데이트 할 수 없습니다. XLOCK이 필요한지 확인하기 위해 응용 프로그램이 수행하는 작업을 조사합니다.

이것을 말했지만 XLOCK을 제거해도 문제가 해결되지 않을 것입니다. SELECT는 여전히 인덱스에서 공유 잠금을 수행하며 INSERT는 XLOCK이이를 업데이트하기를 원할 것입니다. 공유 잠금과 XLOCK은 객체에 함께 존재할 수 없으므로 교착 상태가 계속 발생합니다. IX_Index1은 MyValue 또는 A 또는 둘 다 여야합니다.

이러한 유형의 교착 상태는 잘못 설계된 색인 및 / 또는 너무 많은 색인으로 인해 종종 발생합니다. 또는 잘못 작성된 코드입니다. 가장 좋은 방법은 다른 인덱스를 사용하기 위해 선택을 다시 작성할 수있는 방법이 있는지 확인하는 것입니다.

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