TOP은 실행 계획에 어떤 영향을 미칩니 까?


35

최적화하려는 중간 정도의 복잡한 쿼리의 경우 TOP n절 을 제거 하면 실행 계획이 변경됩니다. 쿼리 TOP n에 데이터베이스 엔진이 포함 되면 TOP절을 무시하고 쿼리를 실행 한 다음 결국에는 결과 집합 을 요청 된 n 개의 행 수로 줄입니다. 그래픽 실행 계획은 이것이 사실임을 나타내는 것 같습니다 – TOP"마지막"단계입니다. 그러나 더 진행되고있는 것으로 보입니다.

내 질문은 TOP n 절이 쿼리 실행 계획에 어떻게 (그리고 왜) 영향을 미칩니 까?

다음은 제 경우에 진행되고있는 것의 단순화 된 버전입니다.

쿼리가 A와 B라는 두 테이블의 행과 일치합니다.

TOP절이 없으면 옵티마이 저는 테이블 A에서 19k 개의 행과 테이블 B에서 46k 개의 행이있을 것으로 추정합니다. 리턴 된 실제 행 수는 A의 경우 16k이고 B의 경우 13k입니다. 해시 일치는이 두 결과 세트를 결합하는 데 사용됩니다. 총 69 개의 ​​행 (정렬이 적용됨). 이 쿼리는 매우 빠르게 발생합니다.

내가 TOP 1001최적화를 추가 하면 해시 일치를 사용하지 않습니다. 대신 먼저 테이블 A (동일한 추정 / 실제 19k / 16k)의 결과를 정렬하고 테이블 B에 대해 중첩 루프를 수행합니다. 테이블 B의 예상 행 수는 이제 1이며 이상한 점은 테이블에 TOP n직접 영향을 미친다는 것입니다. B에 대한 예상 실행 수 (인덱스 탐색) – 항상 2n + 1 또는 내 경우에는 2003으로 나타납니다 .이 추정값은 변경하면 그에 따라 변경 TOP n됩니다. 물론 이것은 중첩 조인이므로 실제 실행 수는 16k (테이블 A의 행 수)이며 쿼리 속도가 느려집니다.

실제 시나리오는 좀 더 복잡하지만 기본 아이디어 / 동작을 캡처합니다. 인덱스 탐색을 사용하여 두 테이블을 모두 검색합니다. 이것은 SQL Server 2008 R2 Enterprise 버전입니다.


쿼리에 ORDER BY절이 있습니다. TOP계획 에서이 정렬이 발생하는 위치에 변경 사항을 추가 하지만 테이블 B에 대한 인덱스 검색 실행 횟수에 어떤 영향을 미치는지에 대해 더 관심이 있습니다 ... (물론 두 가지는 관련이 있습니다-알 수 없음)
David

1
관련 토론 : FAST num_rows쿼리 힌트
Remus Rusanu

답변:


38

쿼리에 TOP n이 포함 된 경우 데이터베이스 엔진은 TOP 절을 무시하고 쿼리를 실행 한 다음 결국에는 결과 집합을 요청 된 n 개의 행 수로 줄입니다. 그래픽 실행 계획은 이것이 사실임을 나타내는 것 같습니다. TOP은 "마지막"단계입니다. 그러나 더 진행되고있는 것으로 보입니다.

위의 문구가 표시되면 쿼리 실행 방법에 대한 잘못된 정신 그림이 있다고 생각합니다. 쿼리 계획의 연산자는 단계 가 아닙니다 (이전 단계 의 전체 결과 집합 이 다음 단계 에 의해 평가됨).

SQL Server는 파이프 라인 실행 모델을 사용합니다 . 여기서 각 연산자는 Init () , GetRow ()Close () 와 같은 메서드를 노출합니다 . 애즈 GetRow () 이름이 암시 운영자는 (부모로서 오퍼레이터에 의해 요구되는) 요구에 한 번에 하나 개의 행을 생성한다. 이 내용은 Books Online Logical and Physical Operators 참조 서 에 나와 있으며 내 블로그 게시물 인 쿼리 계획이 거꾸로 실행되는 이유에 자세히 설명되어 있습니다. 이 행 단위 모델은 쿼리 실행을위한 올바른 직관을 형성하는 데 필수적입니다.

내 질문은, TOPn 절이 쿼리 실행 계획에 어떤 영향을 미치는가 ?

TOP, 세미 조인 및 FAST n 쿼리 힌트 와 같은 일부 논리적 작업 은 쿼리 옵티마이 저가 실행 계획을 대체하는 비용에 영향을줍니다. 기본 아이디어는 하나의 가능한 계획 형태가 모든 행을 리턴하도록 최적화 된 다른 계획보다 첫 n 개의 행을 더 빨리 리턴 할 수 있다는 것입니다.

예를 들어, 인덱스 중첩 루프 조인이 적은 수의 행을 반환하는 가장 빠른 방법 인 경우가 많지만 스캔과의 해시 또는 병합 조인이 더 큰 세트에서 더 효율적일 수 있습니다. 쿼리 옵티마이 저가 이러한 선택에 대한 이유 는 논리 연산 트리의 특정 지점에서 행 목표 를 설정하는 것 입니다.

행 목표는 쿼리 계획 대안의 비용이 드는 방식을 수정합니다. 본질적으로 옵티마이 저는 전체 결과 세트가 필요한 것처럼 각 연산자의 비용을 계산하여 시작하고 적절한 지점에서 행 목표를 설정 한 다음 계획 트리에서 다시 조사해야 할 행 수를 추정합니다. 행 목표를 달성합니다.

예를 들어, 논리 TOP(10)는 논리 쿼리 트리의 특정 지점에서 행 목표 10을 설정합니다. 행 목표까지 이어지는 연산자 비용은 행 목표를 달성하기 위해 생성해야하는 행 수를 추정하도록 수정됩니다. 이 계산은 복잡해질 수 있으므로 완전히 작동하는 예제 와 주석이 달린 실행 계획 으로이 모든 것을 이해하기가 더 쉽습니다 . 행 목표는 조인 유형을 선택하는 것 이상이나 검색 및 조회가 스캔보다 선호되는지에 영향을 줄 수 있습니다. 자세한 내용은 여기를 참조 하십시오 .

항상 그렇듯이 행 목표를 기반으로 선택된 실행 계획에는 옵티마이 저의 추론 능력과 제공된 정보의 품질이 적용됩니다. 행 목표를 가진 모든 계획이 실제로 필요한 행 수를 더 빨리 생성하는 것은 아니지만 원가 계산 모델에 따라 가능합니다.

행 목표 계획이 더 빠르지 않은 경우 일반적으로 자연스럽게 선택된 계획이 최상이되도록 쿼리를 수정하거나 더 나은 정보를 최적화 프로그램에 제공하는 방법이 있습니다. 귀하의 경우에 적합한 옵션은 코스의 세부 사항에 따라 다릅니다. 행 목표 기능은 일반적으로 매우 효과적입니다 ( 병렬 실행 계획에 사용될 때주의해야 할 버그 가 있음).

특정 쿼리 및 계획은 여기에서 자세한 분석에 적합하지 않을 수 있지만 (원하는 경우 실제 실행 계획을 제공해야 함) 여기에 요약 된 아이디어를 통해 발전 할 수 있기를 바랍니다.


12

TOP을 사용하면 옵티마이 저가 적은 작업을 수행 할 수있는 기회를 보게됩니다. 10 행을 요청하면 전체 세트를 소비하지 않아도됩니다. 따라서 TOP 연산자를 훨씬 더 오른쪽으로 밀 수 있습니다. 충분히 수신 될 때까지 다음 연산자 (오른쪽)에서 행을 계속 요청합니다.

TOP이 없으면 쿼리는 데이터를 맨 마지막에 정렬합니다. 엔진이 조인으로 충족 될 행 수를 미리 알 수있는 경우 TOP을 왼쪽에 배치하여 유사한 계획을 사용하는 것이 좋습니다. 그러나 해시 일치를 상대적으로 높이고 병합 조인에 대한 옵션이 없기 때문에 최적화 프로그램은 TOP을 오른쪽으로 더 필터링하는 것을 선호 할 수 있습니다.

테이블 B가 쿼리되면 한 번에 단일 행을 가져옵니다. 그렇기 때문에 추정치는 1입니다. 또한 해당 행의 50 % 만 찾을 수 있다고 가정합니다. 그래서 그것을 찾으려면 2n + 1 탐색이 필요하다고 생각합니다.


데이터를 가져 오는 방식에 따라 예상 행 수가 변경되는 것은 옳지 않은 것 같습니다. 데이터를 가져 오는 방법이 카디널리티에 영향을 미치지 않아야합니다. 가져 오는 방식의 변경 사항이 대신 실행 횟수에 반영됩니다. 맞습니까?
David

"예상 행 수"는 실행 당입니다. Nested Loop에서는 두 번 이상 실행될 가능성이 큽니다.
Rob Farley

이것은 실제 행 수와 (실제) 실행 수와는 다른 동작입니다. 실제 계획에 16,834 개의 실제 실행과 15,407 개의 실제 행이 표시되면 16k 탐색을 수행했지만 술어와 일치하는 15k 만 발견했음을 의미합니다. 실행 당 15k 행을 의미하는 경우 이는 15k * 16k = 2 억 4 천 2 백만 행으로, 테이블보다 약 10 배 더 큽니다.
David

또한, 나는 당신의 대답의 마지막 진술을 확신하지 못합니다. 2n + 1이 "it"을 찾으려고 할 때 "it"는 무엇을 의미합니까? 확실히 하나의 행이 아니십니까? 옵티마이 저가 A의 특정 행에 대해 B와 일치 할 확률이 50 %이므로 B에서 1001 개의 일치 항목을 얻으려면 A에서 2003 개의 행을 "시도"해야한다고 가정합니까? 이 동작은 Microsoft의 어느 곳에 나 문서화되어 있습니까? 그리고 그 TOP절 과 어떤 관련이 있습니까? 답변 / 환자 주셔서 감사합니다.
David

예, 예상 행은 실행 당입니다. 실제 행은 총계입니다. 연산자가 동일한 행을 여러 번 반환하는 것을 쉽게 설명 할 수 있으므로 테이블에있는 것보다 더 많은 행을 반환하는 데 문제가 없습니다.
Rob Farley
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.