NOLOCK 힌트는 반환 된 레코드의 순서를 변경합니다


11

테이블 Client필드 에 클러스터형 인덱스가 있습니다 LastName.

단순히 테이블에서 모든 레코드를 덤프하면 (nolock)힌트가 문제의 쿼리에서 사용 되지 않는 한 알파벳 순서로 나타납니다 . 힌트는 레코드 순서를 변경합니다. 그래? 다른 세션에 해당 테이블의 변경 사항이있는 열린 트랜잭션 sp_who2이 없습니다 (적어도 나에게 아무것도 표시하지 않음).

순서의 차이를 어떻게 설명 할 수 있습니까?

주석에서 가져온 추가 정보 :

  1. 주문이 없습니다. 비 클러스터형 인덱스가 순서를 시행해야합니까?

  2. 클러스터형 인덱스를 지정하는 인덱스 힌트를 사용하더라도 쿼리는 여전히 다른 순서를 반환합니다. 그들은해야합니까? nolock계획을 눈에 띄게 변경하지 않고 반환 된 레코드의 순서를 변경하는 이유 가 궁금 합니다.

  3. 나는 그들에게 (nolock)[쿼리 힌트]를 제외하고는 WinDiff를했다 .


21
힌트는 순서를 변경하지 않습니다. 변경할 수있는 순서가 없기 때문에
a_horse_with_no_name

답변:


47

ORDER BY절이 없는 정렬 된 결과 집합의 모양은 종종 인덱스 순서로 행을 검색하는 스캔의 결과입니다. 인덱스 순서 스캔이 일반적으로 기본 READ COMMITTED분리 레벨 에서 선택되는 한 가지 이유 는 동일한 행이 여러 번 발생하거나 일부 행을 완전히 건너 뛰는 등의 원하지 않는 동시성 이상이 발생할 가능성을 줄이기 때문입니다. 이에 대해서는 격리 수준에 대한 이 일련의 기사를 포함하여 여러 곳에서 자세히 설명 합니다.

NOLOCK테이블 힌트를 사용하면 이 동작이 완화되고 테이블에 대한 액세스가보다 관용적 인 READ UNCOMMITTED격리 수준에서 수행되므로 인덱스 순서 대신 할당 순서로 데이터를 스캔 할 수 있습니다 . 해당 링크에 설명 된대로 할당 순서 또는 인덱스 순서 스캔 사용 여부에 대한 결정은 스토리지 엔진에 맡겨집니다. 이 선택은 쿼리 계획을 변경하지 않고 실행간에 변경 될 수 있습니다 .

이것은 매우 추상적으로 들릴 수 있지만 AdventureWorks2012 데이터베이스 에 대해 문서화되지 않은 함수를 사용하는 일부 쿼리를 사용하면보다 쉽게 ​​시연 할 수 있습니다 .

USE AdventureWorks2012;
GO
-- Appears to be ordered by BusinessEntityID
-- File:Page:Slot goes up and down several times
-- Show physical locations with sys.fn_PhysLocFormatter (undocumented)
SELECT
    P.BusinessEntityID,
    [(File:Page:Slot)] =
        sys.fn_PhysLocFormatter(%%physloc%%)
FROM Person.Person AS P;

-- Same query with TABLOCK or NOLOCK
-- Allocation-order (IAM) scan
-- Now appears to be ordered by File:Page:Slot instead of BusinessEntityID
SELECT P.BusinessEntityID,
    [(File:Page:Slot)] =
        sys.fn_PhysLocFormatter(%%physloc%%)
FROM Person.Person AS P WITH (NOLOCK);

쿼리 결과

Paul White 로부터 약간의 수정으로 쿼리가 차용되었습니다 .

마지막으로,이 답변은 정렬 된 결과 집합 의 모양 에 관한 것입니다. 최상위 수준 이 없으면 프레젠테이션 순서보장되지 않습니다ORDER BY .

할당 순서 스캔은 테이블 레벨 잠금이 확보되거나 데이터베이스가 읽기 전용 모드 인 경우와 같은 다양한 기타 상황에서 발생할 수 있습니다. 병렬 처리는 데이터가 반환되는 순서에 영향을 줄 수도 있습니다. 요점은을 포함하지 않으면 ORDER BY순서 데이터가 반환되는 순서는 설계에 따라 시간이 지남에 따라 달라질 수 있다는 것입니다.


7
감사하지 않은 시도보다 훨씬 구체적입니다. 요점은 물론 마지막 두 단락에 있습니다. "왜"는 결국 중요하지 않습니다. 어쩌면 당신은 나보다 그 화음을 치는 것이 더 좋을 것입니다.
Aaron Bertrand

12

단순히 테이블에서 모든 레코드를 덤프하면

그런 다음 어떤 주문도 기 대해서는 안됩니다. 실제로 동일한 쿼리를 여러 번 실행하면 경고없이 다른 순서로 돌아올 수 있습니다. 그 이유는 힌트가 아닌 다른 쿼리 텍스트로 인해 "다른"쿼리 인 두 쿼리가 다른 실행 계획을 가지고 있기 때문입니다. 두 계획이 있지만 ordered: true하나만 포함하거나 주요 데이터 변경 전에 컴파일 된 행이 크게 다름). James가 그의 답변에서 올바르게 설명했듯이 할당 순서 스캔이 수행되고있을 수도 있습니다.

어쨌든 ORDER BYSQL 없이 쿼리를 실행하기 때문에 SQL Server는 순서를 신경 쓰지 않는다고 추론하고 행을 반환하는 가장 효율적인 방법을 결정합니다 (순서를 신경 쓰지 않으면 순서는 신경 쓰지 않습니다) ).

이것을 매우 명확하게하겠습니다 :

특정 주문을 원하거나 기대하는 경우 ORDER BY 절을 추가하십시오

이것은 전에 나타났습니다 :

그리고 나는 그것에 대해 블로그했습니다 :

다음은 ORDER BY절 대신 색인 힌트를 사용하는 것에 대한 귀하의 의견을 언급하기 위해 후자의 인용을 인용합니다 .

힌트 인덱스의 경우에도 인덱스가 사용되지만 (가능한 경우 대부분의 경우 오류) 인덱스가 사용된다고해서 결과가 키에 의해 정렬되어 반환되는 것은 아닙니다. 그 색인. 여전히 ORDER BY인덱스 키를 기준으로 정렬 해야합니다 .

Conor Cunningham은 SQL Server가 쿼리를 처리 할 때 수행하는 작업의 대부분을 직접 담당하는 똑똑한 사람입니다.

ORDER BY다르거 나 예기치 않은 정렬에 대해 불평하기 전에 몇 가지 사항을 읽고 쿼리에 절을 추가 하십시오.


11

James는 이것이 어떻게 작동하는지 잘 설명했지만 한 가지만 반복하고 싶습니다. 순서 함수를 사용하지 않으면 결과 집합의 행 순서는 정의되지 않습니다 . 지정된 순서가 필요한 경우 명시 적 order by절을 사용하십시오. 지정하지 않으면 기본적으로 "클러스터형 인덱스로 주문"이 아니라 "순서를 전혀 신경 쓰지 않습니다"라고 말합니다.

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