연결 연산자가 입력보다 적은 행을 추정하는 이유는 무엇입니까?


20

다음 쿼리 계획 스 니펫에서 Concatenation연산자 ~4.3 billion rows의 행 추정값은 두 입력에 대한 행 추정값의 합 이어야합니다 .

그러나 추정치 ~238 million rows가 산출되어 수백 GB의 데이터를 tempdb에 유출하는 차선책 Sort/ Stream Aggregate전략으로 이어집니다. 이 경우 논리적으로 일관된 견적은을 생성 Hash Aggregate하고 유출을 제거하며 쿼리 성능을 크게 향상 시켰습니다.

SQL Server 2014의 버그입니까? 입력 값보다 낮은 추정값이 합리적 일 수있는 유효한 환경이 있습니까? 어떤 해결 방법이 있습니까?

여기에 이미지 설명을 입력하십시오

전체 쿼리 계획 (익명) 은 다음과 같습니다 . 이 QUERYTRACEON 2363추적 플래그의 출력 또는 유사한 추적 플래그 를 제공하기 위해이 서버에 대한 sysadmin 액세스 권한이 없지만 도움이 될 경우 관리자로부터 이러한 출력을 얻을 수 있습니다.

데이터베이스의 호환성 수준은 120이므로 새로운 SQL Server 2014 Cardinality Estimator를 사용하고 있습니다.

데이터가로드 될 때마다 통계가 수동으로 업데이트됩니다. 데이터 양이 주어지면 현재 기본 샘플링 속도를 사용하고 있습니다. 샘플링 속도가 높을수록 FULLSCAN영향을 줄 수 있습니다.

답변:


21

이 Connect 항목 에서 Campbell Fraser를 인용하려면 :

이러한 "카디널리티 불일치"는 연결이 사용되는 경우를 포함하여 여러 상황에서 발생할 수 있습니다. 최종 계획에서 특정 서브 트리의 추정이 다르게 구조화되었지만 논리적으로 동등한 서브 트리에 대해 수행 되었기 때문에 발생할 수 있습니다. 카디널리티 추정의 통계적 특성으로 인해 서로 다르지만 논리적으로 동등한 트리에서 추정한다고해서 동일한 추정치를 얻을 수있는 것은 아닙니다. 따라서 전체적으로 예상되는 일관성이 보장되지 않습니다.

조금만 더 설명하자면 : 내가 설명하고 싶은 방법은 초기 카디널리티 추정 (비용 기반 최적화가 시작되기 전에 수행됨)이 전체 "초기 트리"가 처리되기 때문에 "일관된"카디널리티 추정을 생성한다는 것입니다. 이전의 것에 직접 의존하는 추정.

비용 기반 최적화 중에 계획 트리의 일부 (하나 이상의 운영자)를 탐색하고 대안으로 대체 할 수 있으며, 각각의 카디널리티 추정 필요할 수 있습니다 . 어떤 추정치가 다른 추정치보다 일반적으로 더 좋을지에 대한 일반적인 방법은 없으므로 "일관되지 않은"최종 계획으로 끝날 수 있습니다. 이것은 단순히 최종 계획을 형성하기 위해 "계획의 비트"를 스티칭 한 결과입니다.

그러나 SQL Server 2014에 도입 된 새로운 카디널리티 추정기 (CE)에 대한 세부적인 변경 사항이 있었 으므로 원래 CE의 경우보다 다소 덜 일반적입니다.

최신 누적 업데이트로 업그레이드하고 4199의 옵티 마이저 수정 프로그램이 켜져 있는지 확인하는 것 외에 주요 옵션은 통계 / 인덱스 변경 (인덱스 누락에 대한 경고 표시) 및 업데이트를 시도하거나 쿼리를 다르게 표현하는 것입니다. 목표는 필요한 행동을 보여주는 계획을 세우는 것입니다. 그런 다음 예를 들어 계획 가이드를 사용하여 고정 할 수 있습니다.

익명화 된 계획은 세부 사항을 평가하기 어렵지만 비트 맵이 '최적화'(Opt_Bitmap) 또는 사후 최적화 (Bitmap) 다양성인지 확인하기 위해 신중하게 살펴볼 것입니다. 또한 필터가 의심됩니다.

그래도 행 개수가 정확하면 columnstore에서 도움이 될 수있는 쿼리처럼 보입니다. 일반적인 이점을 제외하고 배치 모드 연산자에 대해 동적 메모리 부여를 활용할 수 있습니다 ( 추적 플래그 9389 가 필요할 수 있음).


7

SQL Server 2012 (11.0.6020)에서 다소 간단한 테스트 베드를 작성하면을 통해 두 개의 해시 일치 쿼리가 연결된 계획을 다시 만들 수 있습니다 UNION ALL. 내 테스트 베드에 잘못된 추정치가 표시되지 않습니다. 아마도 이것은 이다 는 SQL 서버 2014 CE 문제.

실제로 280 개의 행을 반환하는 쿼리에 대해 133.785 개의 행이 예상되지만 아래에서 더 자세히 볼 수 있습니다.

IF OBJECT_ID('dbo.Union1') IS NOT NULL
DROP TABLE dbo.Union1;
CREATE TABLE dbo.Union1
(
    Union1_ID INT NOT NULL
        CONSTRAINT PK_Union1
        PRIMARY KEY CLUSTERED
        IDENTITY(1,1)
    , Union1_Text VARCHAR(255) NOT NULL
    , Union1_ObjectID INT NOT NULL
);

IF OBJECT_ID('dbo.Union2') IS NOT NULL
DROP TABLE dbo.Union2;
CREATE TABLE dbo.Union2
(
    Union2_ID INT NOT NULL
        CONSTRAINT PK_Union2
        PRIMARY KEY CLUSTERED
        IDENTITY(2,2)
    , Union2_Text VARCHAR(255) NOT NULL
    , Union2_ObjectID INT NOT NULL
);

INSERT INTO dbo.Union1 (Union1_Text, Union1_ObjectID)
SELECT o.name, o.object_id
FROM sys.objects o;

INSERT INTO dbo.Union2 (Union2_Text, Union2_ObjectID)
SELECT o.name, o.object_id
FROM sys.objects o;
GO

SELECT *
FROM dbo.Union1 u1
    INNER HASH JOIN sys.objects o ON u1.Union1_ObjectID = o.object_id
UNION ALL
SELECT *
FROM dbo.Union2 u2
    INNER HASH JOIN sys.objects o ON u2.Union2_ObjectID = o.object_id;

내가 생각하는 이유는 결과 두 통계의 부족 주위에 그 UNION을하다 합류했다. SQL Server는 통계가 부족한 경우 열의 선택성에 대해 대부분의 경우에 대한 추측을해야합니다.

조 자루는에 흥미있는 읽기 여기를 .

A에 대한 UNION ALL, 우리가 그러나 SQL 서버부터 행 사용하고, 노동 조합의 각 구성 요소에 의해 반환 된 행 정확히 총 수를 볼 수 있습니다 말을하는 것이 안전 추정 의 두 구성 요소에 대해 UNION ALL, 우리는 볼 수는 총 추가 평가 모두에서 행을 연결 연산자에 대한 추정값을 제시합니다.

위의 예에서의 각 부분에 대한 예상 행 수 UNION ALL는 66.8927이며, 합산하면 133.785와 같으며 연결 연산자의 예상 행 수에 대해 알 수 있습니다.

위의 통합 쿼리에 대한 실제 실행 계획은 다음과 같습니다.

여기에 이미지 설명을 입력하십시오

"추정 된"vs "실제적인"행 수를 볼 수 있습니다. 필자의 경우 두 해시 일치 연산자에서 반환하는 "추정 된"행 수를 추가하면 연결 연산자에 표시된 양이 정확히 같습니다.

폴 화이트의 게시물에 권장 된대로 추적 2363 등에서 출력을 얻으려고합니다. 또는 OPTION (QUERYTRACEON 9481)쿼리에서 사용 하여 버전 70 CE되돌아 가서 문제가 "수정"되는지 확인할 수 있습니다.


1
감사. "이유가 UNION 된 두 개의 조인에 대한 통계가 부족한 이유"는 후속 조인 또는 집계 (UNION 이후에 발생)에 큰 영향을 미친다는 것을 분명히 알았습니다. 실제로 SQL 2014는 내 경험상 SQL 2012보다 이것을 더 잘 처리합니다. 여기 예를 들어 과거에 사용했던 간단한 테스트 스크립트는 다음과 같습니다 gist.github.com/anonymous/1497112d8b25ab8fb782a04569959c68는 그러나, 나는 연결 연산자는이 조인 값의 분포에 대한 정보 같은 종류의 필요 것이라고 생각하지 것이다 필요로 할 수도있다.
Geoff Patterson

연결 정확하게 수행하기 위해 통계가 필요 하지 않음에 동의 합니다. 들어오는 행 추정값을 안정적으로 추가하여 출력 할 행 수를 잘 이해할 수 있어야합니다. @PaulWhite가 그의 대답에서 알 수 있듯이 놀랍게도 항상 그런 것은 아닙니다. 나에게 여기서의 테이크 아웃은 단순 해 보이지만 실제로는 그렇지 않을 수도 있습니다. 나는 당신이 한 방식으로 질문을해서 기쁘다. 나는 당신이 계획을 익명화하지 않아도되기를 바란다. 실제 쿼리를 보는 것은 흥미로울 것이다.
맥스 버논
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.