Tablock 힌트는 교착 상태를 트리거합니다


10

최소한의 로깅을 사용하여 두 개의 데이터 세트를 병렬로 실행되는 두 개의 SQL 실행 태스크와 다음 형식의 SQL을 사용하여 빈 힙 테이블에 삽입했습니다.

INSERT INTO Table (TABLOCK) SELECT FROM ...

작업이 약간 중단 된 후 SQL 태스크 중 하나가 교착 상태의 희생자가되었습니다. 다음은 교착 상태 그래프의 XML 출력입니다.

누군가 후드 아래에서 무슨 일이 있었는지 설명 할 수 있습니까?

  <resource-list>
   <objectlock lockPartition="0" objid="1586156746" subresource="FULL" dbid="7" objectname="dbo.TargetTable" id="lock7374a00" mode="IX" associatedObjectId="1586156746">
    <owner-list>
     <owner id="process9609dc8" mode="Sch-S"/>
     <owner id="process9609dc8" mode="IX"/>
    </owner-list>
    <waiter-list>
     <waiter id="process5e13048" mode="X" requestType="convert"/>
    </waiter-list>
   </objectlock>
   <objectlock lockPartition="0" objid="1586156746" subresource="FULL" dbid="7" objectname="dbo.TargetTable" id="lock7374a00" mode="IX" associatedObjectId="1586156746">
    <owner-list>
     <owner id="process5e13048" mode="Sch-S"/>
     <owner id="process5e13048" mode="IX"/>
    </owner-list>
    <waiter-list>
     <waiter id="process9609dc8" mode="X" requestType="convert"/>
    </waiter-list>
   </objectlock>
  </resource-list>

대부분의 경우 두 개의 SQL 실행 작업이 병렬로 성공적으로 실행될 수 있다는 것을 알았 기 때문에 상황이 훨씬 까다로워졌습니다. 아래에서 시도하십시오 :

Create table dbo.TablockInsert (c1 int, c2 int, c3 int)

--then issue the script in two Execute Sql Task in parallel you won't fail:
insert into dbo.TablockInsert(TABLOCK) SELECT 1, 1, 1

유일한 차이점은 SELECT ... FROM ... 문이므로 SELECT ... FROM ... 문은 잠금 모드에 영향을 줄 수 있습니까?


교착 상태를 방지하기 위해 TABLOCK 대신 TABLOCKX를 지정할 수 있습니다. 이로 인해 테이블에 대한 액세스도 직렬화되지만 최소한의 로깅이 유지됩니다.
Dan Guzman

답변:


8

데이터로드 성능 가이드 SQL 서버 2008 용으로 작성되었지만 지금까지 내가 말할 수있는대로 Microsoft는 힙이 지역에 어떤 개선을하지했다. 로드 시나리오에 대한 인용문은 다음과 같습니다.

비어 있고 파티션되지 않은 테이블 대량로드

파티션되지 않은 테이블에 데이터를로드하는 것은 간단한 조작이지만 여러 가지 방법으로 최적화 할 수 있습니다.

...

선택된 벌크 메소드가 테이블에서 BU (Bulk Update) 잠금을 발행하는 경우에만 힙에 대한 복수의 동시 삽입 조작이 가능합니다. 두 개의 대량 업데이트 (BU) 잠금이 호환되므로 두 개의 대량 작업을 동시에 실행할 수 있습니다.

이 시나리오에서는 INSERT… SELECT 와 SELECT INTO 모두 단점이 있습니다. 이 두 작업 모두 대상에서 배타적 (X) 테이블 수준 잠금을 사용합니다. 이는 주어진 시간에 단 하나의 벌크로드 조작 만 실행할 수 있으며 확장 성을 제한 함을 의미합니다. 그러나 TABLOCK 힌트를 지정하면 BCP, BULK INSERT 및 Integration Services는 모두 대량 업데이트 (BU) 잠금을 수행 할 수 있습니다.

중요한 부분은로 BU 잠금을 얻지 못한다는 것입니다 INSERT ... SELECT. 항상 테이블에 독점 잠금을 부여하므로 한 번에 하나만 INSERT실행할 수 있습니다.

의견에서 당신은 100k 행 이하를 삽입 할 것이고 다른 프로세스는 삽입하는 동안 테이블에서 실행되지 않을 것이라고 말했습니다. 두 개의 INSERT 쿼리를 데이터베이스에 보낼 때 세 가지 중 하나가 발생할 것으로 예상합니다.

  1. 한 인서트가 먼저 작동하고 다른 인서트를 막습니다. 두 번째 인서트는 첫 번째 인서트가 완료 될 때까지 기다립니다.
  2. 두 번째 인서트가 시작되기 전에 하나의 인서트가 완료됩니다. 명시적인 차단은 없지만 동시에 실행되지는 않습니다.
  3. 교착 상태가 발생하고 하나의 삽입 만 성공적으로 완료됩니다.

모든 경우 TABLOCKX에 쿼리에 힌트를 추가하여 이점을 얻거나 아프지 않기 때문에 교착 상태를 해결하는 것이 좋습니다. 교착 상태가 발생하는 이유를 알고 싶다면 다른 대답을 찾아야합니다.

실제로 병렬 삽입이 필요한 다른 시나리오에서 BU 문제를 해결하는 두 가지 방법은 힙을 분할하고 각 세션을 별도의 분할 영역에 삽입하거나 BCP, BULK INSERT 또는 Integration Services를 통해 데이터를로드하는 것입니다. .


답변 주셔서 감사하지만 교착 상태가 발생한 상황은 지금까지 내가 가진 유일한 사례입니다. 대부분의 경우 INSERT INTO WITH (TABLOCK) SELECT FROM을 동시에 발행하면 작업이 실패하지 않습니다. BTW, SQL SERVER 2008 R2를 사용하고 있습니다. 내 질문에 성공적인 예를 추가했습니다.
SqlWhale

아마도 실패했을 경우 @tec은 실제로 직렬로 실행됩니다. 계획 컴파일과 같은 특정 시작 시간이있을 때만 문제가 발생했을 수 있습니다.
마틴 스미스

@MartinSmith 프로젝트에서 문제가 발생한 쿼리는 SELECT 1 예제보다 훨씬 복잡하여 컴파일 오버 헤드가 더 많이 필요하지만 몇 테이블에서 읽습니다. 더 복잡한 쿼리로 이러한 유형의 교착 상태를 재현하려고합니다.
SqlWhale

@TecKnowNothing 몇 개의 행을 삽입합니까? 프로세스는 하루에 몇 번 실행됩니까? 데이터가로드되는 동안 다른 쿼리가 테이블에서 SELECT를 수행합니까?
Joe Obbish

@JoeObbish 1. 여기서 행 수는 문제가되지 않는다고 생각합니다. 각 쿼리마다 4000-70000 만 있고 큐브 사용을 위해 매우 집계 된 데이터입니다. 2. 여전히 테스트 단계에 있으며 하루에 한 번 실행됩니다. 3. 타겟 테이블에서 다른 것을 읽는 것이 없습니다.
SqlWhale

4

당신은 dbo.TargetTable두 세션에서 삽입 하고 둘 다 TABLOCK힌트를 사용하고 있습니다. 두 프로세스 process9609dc8process5e13048프로세스 홀드 Sch-SIX잠금은 서로 호환되므로 두 프로세스가 동시에 보유 할 수 있습니다. 그러나 둘 다 IXlock을 Exclusive X유형 으로 변환하려고 합니다. X잠금 장치는 서로 호환되지 않습니다. 따라서 SQL Server는 세션 중 하나를 서로를 기다리지 않고 교착 상태로 선택했습니다.

기본 교착 상태 정보.

잠금 호환성 (데이터베이스 엔진) 차트.

교착 상태 감지 및 종료.

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