SQL Server 인덱스 업데이트 교착 상태


13

동시에 실행될 때 교착 상태를 일으키는 2 개의 쿼리가 있습니다.

쿼리 1-인덱스 (index1)에 포함 된 열을 업데이트합니다.

update table1 set column1 = value1 where id = @Id

table1에서 X-Lock을 가져온 다음 index1에서 X-Lock을 시도합니다.

쿼리 2 :

select columnx, columny, etc from table1 where {some condition}

index1에서 S-Lock을 수행 한 다음 table1에서 S-Lock을 시도합니다.

동일한 쿼리를 유지하면서 교착 상태를 방지하는 방법이 있습니까? 예를 들어 업데이트 전에 업데이트 트랜잭션의 인덱스에서 X-Lock을 수행하여 테이블과 인덱스 액세스가 동일한 순서로 유지되도록 할 수 있습니다. 교착 상태를 방지해야합니까?

격리 수준은 읽기 커밋입니다. 인덱스에 행 및 페이지 잠금이 사용됩니다. 동일한 레코드가 두 쿼리에 모두 참여할 수 있습니다. 교착 상태 그래프에서 매개 변수를 표시하지 않으므로 알 수 없습니다.

교착 상태 그래프

답변:


11

동일한 쿼리를 유지하면서 교착 상태를 방지하는 방법이 있습니까?

교착 상태 그래프는이 특정 교착 상태가 책갈피 조회 (이 경우 RID 조회)와 연관된 변환 교착 상태임을 보여줍니다.

교착 상태 그래프

질문에서 알 수 있듯이 일반적인 교착 상태 위험은 쿼리가 동일한 리소스에 대해 서로 다른 순서로 호환되지 않는 잠금을 얻을 수 있기 때문에 발생합니다. SELECT쿼리 반면 인해 RID 룩업 테이블에 인덱스 전에 액세스해야 UPDATE다음 표 제 쿼리 수정 인덱스.

교착 상태를 제거하려면 교착 상태 성분 중 하나를 제거해야합니다. 주요 옵션은 다음과 같습니다.

  1. 비 클러스터형 인덱스 커버링을 만들어 RID 조회를 피하십시오. SELECT쿼리에서 26 개의 열을 반환 하기 때문에이 방법은 실용적이지 않습니다 .
  2. 클러스터형 인덱스를 만들어 RID 조회를 피하십시오. 여기에는 열에 클러스터형 인덱스를 만드는 것이 포함됩니다 Proposal. 이 열이 유형 인 것처럼 보이지만 uniqueidentifier더 넓은 문제에 따라 클러스터형 인덱스에 적합하지 않을 수도 있습니다.
  3. READ_COMMITTED_SNAPSHOT또는 SNAPSHOT데이터베이스 옵션 을 활성화하여 읽을 때 공유 잠금을 사용하지 마십시오 . 이를 위해서는 특별히 설계된 차단 동작과 관련하여 신중한 테스트가 필요합니다. 트리거 코드는 논리가 올바르게 수행되는지 테스트해야합니다.
  4. 쿼리 의 READ UNCOMMITTED격리 수준을 사용하여 읽을 때 공유 잠금을 사용하지 마십시오 SELECT. 모든 일반적인주의 사항이 적용됩니다.
  5. 단독 응용 프로그램 잠금을 사용하여 해당 두 쿼리를 동시에 실행하지 마십시오 ( sp_getapplock 참조 ).
  6. 동시성을 피하려면 테이블 잠금 힌트를 사용하십시오. 이것은 질문 5에서 확인 된 것만이 아니라 다른 쿼리에 영향을 줄 수 있기 때문에 옵션 5보다 큰 망치입니다.

테이블과 인덱스 액세스가 동일한 순서로 유지되도록 업데이트 전에 업데이트 트랜잭션의 인덱스에서 X-Lock을 어떻게 수행 할 수 있습니까?

업데이트를 명시 적 트랜잭션으로 래핑하고 업데이트 전에 클러스터되지 않은 인덱스 값에 SELECT대한 XLOCK힌트를 사용하여 이를 수행 할 수 있습니다. 이는 비 클러스터형 인덱스의 현재 값이 무엇인지 알고, 실행 계획을 올바르게 세우고,이 추가 잠금을 수행하는 모든 부작용을 정확하게 예상하는 데 달려 있습니다. 또한 잠금 엔진 이 중복 된 것으로 판단되면 잠금 장치가 걸리지 않을 정도로 똑똑하지 않은 잠금 엔진에 의존합니다 .

요컨대, 이것이 원칙적으로 실현 가능하지만 권장하지는 않습니다. 무언가를 놓치거나 창의적인 방식으로 자신을 능가하는 것은 너무 쉽습니다. 이러한 교착 상태를 피하고 다시 시도하는 대신 실제로 교착 상태를 피해야하는 경우 위에 나열된보다 일반적인 솔루션을 살펴 보는 것이 좋습니다.


문제를 자세히 살펴보면 변경하지 않는 것이 가장 좋습니다. 내가 원래 깨달았 던 더 일반적인 문제입니다.
Dale K

1

나는 종종 비슷한 문제가 발생하며 여기에 내가 접근하는 방법이 있습니다.

  1. set deadlock priority low;선택에 추가 하십시오. 교착 상태가 발생하면이 쿼리가 교착 상태의 피해자가됩니다.
  2. 차단 쿼리가 완료 될 수 있도록 잠시 동안 대기 / 절전 한 후 교착 상태 (또는 시간 종료)로 인해 선택에 실패하면 선택 사항을 자동으로 재 시도하도록 애플리케이션 내에서 설정 재시도 로직을 다시 시도하십시오.

참고 : select명시 적 다중 문 트랜잭션의 일부인 경우 실패한 문뿐만 아니라 전체 트랜잭션을 다시 시도해야합니다. 그렇지 않으면 예기치 않은 결과가 발생할 수 있습니다. 이 하나 인 경우 select당신은 괜찮지 만 문 경우 xn트랜잭션 (transaction)가, 그럼 그냥 당신이 모든 재 시도 할 n재시도시에 문을.


감사-쿼리는 기본적으로 자동 교착 상태 대상입니다. 그리고 우리는 이미 강력한 재시도 메커니즘을 가지고 있습니다.
Dale K
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.