2

스냅 샷 격리가이 문제를 해결할 것이라는 것을 알고 있지만, 오버 헤드를 피할 수 있도록 NOLOCK이이 특정 케이스에서 안전한지 궁금합니다.이 상황에서 UNCOMMITTED/NOLOCK은 안전합니까?

drop table Data 

create table Data 
(
    Id BIGINT NOT NULL, 
    Date BIGINT NOT NULL, 
    Value BIGINT, 
    constraint Cx primary key (Date, Id) 
) 

create nonclustered index Ix on Data (Id, Date) 

이제까지 테이블에는 업데이트가 없습니다 :

은 내가 이렇게 보이는 테이블이 있습니다. 삭제는 발생할 수 있지만 테이블의 다른 끝에 영향을주기 때문에 절대로 SELECT와 경쟁해서는 안됩니다. 삽입물은 정기적이며 (ID, 날짜) 색인에 대한 페이지 분할은 매우 일반적입니다. 다음 1 × (ID, 날짜, 삽입은 CX에 잠금을 획득

select top 1 Date, Value from Data where Id = @p0 order by Date desc 

때문에 (값 날짜, 아이디) :

나는 표준 INSERT와 같이 보입니다 SELECT 사이의 교착 상태가), SELECT는 Ix (Id, Date)와 Cx (Date, Id, Value)에 대한 잠금을 획득합니다. 이것은 SELECT가 먼저 Ix를 탐색 한 다음 Cx의 탐색에 조인하기 때문입니다.

클러스터 된 인덱스와 클러스터되지 않은 인덱스를 서로 바꾸면이 사이클이 중단되지만 다른 (더 복잡한) SELECT가있는 사이클이 도입되기 때문에 용인 할 수없는 솔루션입니다.

NOLOCK을 SELECT에 추가하면이 경우 잘못 될 수 있습니까? 반환 할 수 있습니까?

  1. TOP 1을 요청했지만 여러 행이 있습니까?
  2. 행이 존재하고 커밋 되었더라도 행이 없습니다?
  3. 최악의 경우 WHERE 절을 만족하지 않는 행이 있습니까?

나는이 온라인에 대한 책을 읽은 많은 일을했지만, 과다 또는 과소 카운트 이상의 유일한 재현 나는 검사를 포함 (one, two) 보았다. 이것은 추구만을 포함합니다. 제프 앳 우드 has a post에 대해 좋은 토론을 생성 한 NOLOCK 사용. 나는 릭 타운센드에 의해 코멘트에 특히 관심이 : 당신이 더러운 데이터를 읽을 경우

둘째, 당신은 실행 위험이 완전히 잘못된 행을 읽는 것입니다. 예를 들어, 경우 선택이 에게 행을 찾기 위해 인덱스를 읽고, 다음 업데이트는 행의 위치를 변경 (예 : 인해 페이지 분할 또는 클러스터 된 인덱스에 대한 업데이트에) 당신의 선택 간다, 실제 데이터 행을 읽으려면 이 없거나 다른 행이 있어야합니다.

인서트에만 가능하며 업데이트가 없습니까? 그렇다면 삽입 전용 테이블에 대한 내 탐색조차도 위험 할 수 있습니다.


업데이트 : how snapshot isolation works을 알아 내려고 노력하고있어

. 트랜잭션이 테이블 (공유 잠금이없는!)을 읽고 관심있는 행을 찾은 다음 tempdb의 버전 저장소에서 행의 이전 버전을 가져와야하는지 확인하는 행 기반으로 보입니다.

하지만 제 경우에는 행에 둘 이상의 버전이 없으므로 버전 저장소가 무의미한 것처럼 보입니다. 공유 잠금이없는 행이 발견되면 NOLOCK을 사용하는 것과 어떻게 다릅니 까?

답변

7

NOLOCK을 사용하거나 UNCOMMITTED를 사용한다는 것은 일관성을 보장하지 않는다는 의미입니다. 기간.

일관성이 필요한 경우 더러운 읽기를 수행하지 마십시오. 귀하의 전체적인 설명은 향후 릴리스에서 변경 될 수있는 문서화되지 않은 동작에 의존하며, 훨씬 더 나쁜 것은 특정 액세스 플랜에 대한 귀하의 질문에 대한 기대입니다. 쿼리 최적화 프로그램은 적합하다고 판단되는 계획과 프로덕션 환경에서 손상 될 수있는 가정을 자유롭게 선택할 수 있습니다. 다시 정사각형으로 돌아갑니다. 결과에 직면 할 준비가되어 있지 않으면 더러워서는 안됩니다.

이 내용이 적용되는지 확실하지 않은 경우 쿼리/표를 사용하여 달성하려는 내용이 명확하지 않지만이 도움말은 Using tables as Queues 일 수 있습니다.

업데이트 일관성이없는 상태를 읽을 것 NOLOCK 읽기 스냅 샷 읽기는 '실종'을 찾아 낼 것입니다 (예. 오래된 클러스터되지 않은 인덱스 키를 읽고 클러스터 된 인덱스에서 누락 된 행을 쫓아)
버전 저장소의 행 안정적인 데이터의 경우 스 냄샷 읽기가 nolock 읽기와 동일합니다. 버전 저장소의 마술은 데이터가 변경 될 때마다 실행됩니다 (커밋되지 않은 업데이트). 스냅 샷 읽기가 버전 저장소에 들어가고 nolock 읽기가 엉망이되어 포인터를 추적하는 '이전'값 (안정적이고 일관성있는)을 찾습니다. 라 라 랜드.

+0

아, OUTPUT 절이 매우 멋지다. 고마워. 나는이 특정 테이블에서 필요하지 않지만 나중에 사용할 코드를 생각해 볼 수 있습니다. 그리고 요점을 이해합니다. 나는 이미 다른 쿼리 계획의 영향을 경험했습니다. 데드락은 두 스캔을 전체 스캔보다 더 좋게 만들 때까지 발생하지 않습니다. 솔직하게 말해서 나는 이미 스냅 샷 격리에 기대고있었습니다. 그러나 문서화되지 않은 행동을 문서화하는 것은 제가 생산 단계에서 그것을 활용하지 않더라도 저에게 흥미 롭습니다. :) –

+0

원본 질문을 다른 질문과 함께 업데이트했습니다. 감사합니다. –

+0

OK, "오래된 클러스터되지 않은 인덱스 키를 읽고 클러스터 된 인덱스의 누락 된 행으로 이동"하고 싶지 않다는 것에 동의합니다. 문제는 실제로 어떤 행에서도 UPDATE없이 발생합니까? 내가하고있는 모든 작업은 삽입 작업이므로 모든 행의 데이터가 아닌 메타 데이터 만 업데이트됩니다. 나는 SQL Server가 NOLOCK (꽤 높은 수준의 개념)을 사용할 때조차도 메타 데이터 손상을 방지하기 위해 일부 낮은 수준의 일관성 메커니즘을 갖추고 있다고 생각했을 것입니다. –

1

이 경우 NOLOCK은 안전해야합니다. 추가 생각 : 1x 인덱스에 포함 된 컬럼으로 Value를 추가하면 Cx에서 찾기를 제거해야합니다.

create nonclustered index Ix on Data (Id, Date) include (Value) 
+0

위의 사항에 비추어 안전하다고 생각하는 이유를 자세히 설명해 주시겠습니까? 또한 색인에 키가 아닌 열을 포함하는 것을 고려했지만 실제로는 다소 넓습니다 (둘 이상이 있습니다) 상당한 공간을 사용합니다. 그리고 그 복제는 캐시에서 더 유용한 것들을 강제 할 수 있습니다. –

관련 문제