나는 COALESCE
몇 개의 열에서 작업하고 열에 참여하는 것이 좋은 습관이 아니라는 것을 알고 있습니다.
스키마가 3NF + (키 및 제약 조건 포함)이고 쿼리가 관계형이고 주로 SPJG (선택-투영-조인 그룹 기준) 인 경우 우수한 카디널리티 및 분포 추정값을 생성하기는 어렵습니다. CE 모델은 이러한 원칙을 기반으로합니다. 쿼리에서 이례적 이거나 비 관계형 기능 이 많을수록 카디널리티 및 선택성 프레임 워크가 처리 할 수있는 범위에 더 가깝습니다. 너무 멀리 가서 CE는 포기하고 추측 합니다.
대부분의 MCVE 예는 단순한 SPJ (No G)이지만, 단순한 내부 말 조인 (또는 세미 조인)이 아닌 외부 말초 (내부 조인 + 안티-세미 조인으로 모델링 됨)가 있습니다. 외래 키나 다른 제약 조건은 없지만 모든 관계에는 키가 있습니다. 조인 중 하나를 제외하고 모두 일대 다이며, 좋습니다.
와 사이의 다 대다 외부 조인 은 예외입니다 . MCVE에서이 조인의 유일한 기능은의 행을 잠재적으로 복제하는 것입니다 . 이것은 특이한 일입니다.X_DETAIL_1
X_DETAIL_LINK
X_DETAIL_1
단순 등식 술어 (선택) 및 스칼라 연산자도 좋습니다. 예를 들어 attribute compare-equal attribute / constant는 일반적으로 모델에서 잘 작동합니다. 이러한 술어의 적용을 반영하도록 히스토그램 및 빈도 통계를 수정하는 것은 비교적 "쉽습니다".
COALESCE
에 내장되어 CASE
있으며 내부적으로 구현됩니다 IIF
(이것은 IIF
Transact-SQL 언어로 나타나기 전에 사실이었습니다 ). CE 모델 IIF
은 UNION
두 개의 상호 배타적 인 자식으로 구성되며 각각 입력 관계에 대한 선택 프로젝트로 구성됩니다. 나열된 각 구성 요소는 모델을 지원하므로 구성이 비교적 간단합니다. 그럼에도 불구하고 하나의 계층 추상화가 많을수록 최종 결과의 정확성이 떨어지기 때문에 실행 계획이 클수록 안정성과 안정성이 떨어집니다.
ISNULL
반면에 엔진 에는 고유 합니다. 더 이상 기본 구성 요소를 사용하여 빌드되지 않습니다. ISNULL
예를 들어 히스토그램에 효과를 적용하는 것은 NULL
값에 대한 단계를 바꾸는 것 (필요한 경우 압축 )만큼 간단 합니다. 스칼라 연산자가 진행됨에 따라 여전히 불투명하므로 가능한 경우 피하는 것이 가장 좋습니다. 그럼에도 불구하고 일반적으로 CASE
기반 대체 제품 보다 최적화 프로그램에 덜 적합합니다 (최적화에 적합하지 않음) .
CE (70 및 120+)는 SQL Server 표준에 의해서도 매우 복잡합니다. 각 연산자에 간단한 논리 (비밀 수식 포함)를 적용하는 경우는 아닙니다. CE는 키와 기능적 종속성에 대해 알고 있습니다. 빈도, 다변량 통계 및 히스토그램을 사용하여 추정하는 방법을 알고 있습니다. 그리고 특별한 경우, 개선, 점검 및 균형 및 지원 구조가 절대적으로 있습니다. 예를 들어 여러 방법으로 결합 (빈도, 히스토그램)을 추정하고이 둘의 차이를 기반으로 결과 또는 조정을 결정합니다.
다루어야 할 마지막 기본 사항 : 초기 카디널리티 추정은 쿼리 트리의 모든 작업에 대해 아래에서 위로 실행됩니다. 리프 연산자에 대한 선택 성과 카디널리티가 먼저 파생됩니다 (기본 관계). 수정 된 히스토그램 및 밀도 / 주파수 정보는 상위 연산자를 위해 파생됩니다. 트리를 더 높이 올리면 오차가 누적되는 경향으로 추정 품질이 저하되는 경향이 있습니다.
이 단일 종합 종합 추정은 시작점을 제공하며, 최종 실행 계획을 고려하기 전에 발생합니다 (사소한 계획 컴파일 단계 이전에도 발생합니다). 이 시점의 쿼리 트리는 작성된 쿼리 형식의 쿼리를 상당히 밀접하게 반영하는 경향이 있습니다 (하위 쿼리는 제거되고 단순화는 적용됨).
초기 추정 직후 SQL Server는 휴리스틱 조인 재정렬을 수행합니다. 느슨하게 말하면 트리를 재정렬하여 작은 테이블과 높은 선택성 조인을 먼저 배치하려고합니다. 또한 외부 조인 및 교차 제품 전에 내부 조인을 배치하려고합니다. 그 기능은 광범위하지 않습니다. 그들의 노력은 철저하지 않다. 물리적 비용은 고려하지 않습니다 (아직 존재하지 않기 때문에 통계 정보 및 메타 데이터 정보 만 존재 함). 휴리스틱 재정렬은 단순한 내부 동등 트리에서 가장 성공적입니다. 비용 기반 최적화를위한 "더 나은"시작점을 제공하기 위해 존재합니다.
이 결합 카디널리티 추정이 왜 그렇게 큰가요?
MCVE는 "비정상적인"대부분 중복 된 다 대다 조인과 COALESCE
술어에서 동등 조인을 갖습니다 . 운영자 트리에는 또한 내부 조인 last 가 있습니다. 휴리스틱 조인 순서는 트리를 더 선호하는 위치로 이동할 수 없습니다. 모든 스칼라와 투영을 제외하고 결합 트리는 다음과 같습니다.
LogOp_Join [ Card=4.52803e+009 ]
LogOp_LeftOuterJoin [ Card=481577 ]
LogOp_LeftOuterJoin [ Card=481577 ]
LogOp_LeftOuterJoin [ Card=481577 ]
LogOp_LeftOuterJoin [ Card=481577 ]
LogOp_Get TBL: X_DRIVING_TABLE(alias TBL: dt) [ Card=481577 ]
LogOp_Get TBL: X_DETAIL_1(alias TBL: d1) [ Card=70 ]
LogOp_Get TBL: X_DETAIL_LINK(alias TBL: lnk) [ Card=47 ]
LogOp_Get TBL: X_DETAIL_2(alias TBL: d2) X_DETAIL_2 [ Card=119 ]
LogOp_Get TBL: X_DETAIL_3(alias TBL: d3) X_DETAIL_3 [ Card=281 ]
LogOp_Get TBL: X_LAST_TABLE(alias TBL: lst) X_LAST_TABLE [ Card=94025 ]
잘못된 최종 추정치가 이미 적용되었습니다. Card=4.52803e+009
배정 밀도 부동 소수점 값 4.5280277425e + 9 (소수점 4528027742.5)로 내부적으로 인쇄되어 저장됩니다.
원래 쿼리의 파생 테이블이 제거되었으며 프로젝션이 정규화되었습니다. 초기 카디널리티 및 선택성 추정이 수행 된 트리의 SQL 표현은 다음과 같습니다.
SELECT
PRIMARY_ID = COALESCE(d1.JOIN_ID, d2.JOIN_ID, d3.JOIN_ID)
FROM X_DRIVING_TABLE dt
LEFT OUTER JOIN X_DETAIL_1 d1
ON dt.ID = d1.ID
LEFT OUTER JOIN X_DETAIL_LINK lnk
ON d1.LINK_ID = lnk.LINK_ID
LEFT OUTER JOIN X_DETAIL_2 d2
ON dt.ID = d2.ID
LEFT OUTER JOIN X_DETAIL_3 d3
ON dt.ID = d3.ID
INNER JOIN X_LAST_TABLE lst
ON lst.JOIN_ID = COALESCE(d1.JOIN_ID, d2.JOIN_ID, d3.JOIN_ID)
(제외 적으로, 반복 COALESCE
은 최종 계획에도 있습니다-최종 계산 스칼라에서 한 번, 내부 조인의 내부에서 한 번).
마지막 조인에 주목하십시오. 이 내부 결합은 정의 X_LAST_TABLE
에 따라 선택 (결합 술어)이 lst.JOIN_ID = COALESCE(d1.JOIN_ID, d2.JOIN_ID, d3.JOIN_ID)
적용 되는 정의 (카르테 시안 곱) 및 선행 결합 출력 입니다. 직교 곱의 카디널리티는 단순히 481577 * 94025 = 45280277425입니다.
이를 위해 술어의 선택성을 결정하고 적용해야합니다. 주요 정보에 대한 영향과 함께 불투명 확장 COALESCE
트리 ( UNION
및 IIF
, 기억) 의 조합은 초기 "비정상적인"대부분 중복 된 다 대다 외부 결합의 히스토그램 및 빈도를 도출하여 CE가이를 수행 할 수 없음을 의미합니다. 일반적인 방법으로 수용 가능한 추정치를 도출합니다.
결과적으로 추측 논리에 들어갑니다. 추측 논리는 "교육받은"추측과 "교육되지 않은"추측 알고리즘의 계층으로 시도되어 적당히 복잡합니다. 추측에 대한 더 나은 근거가 발견되지 않으면 모형은 최후의 추측을 사용합니다. 평등 비교의 경우 : sqllang!x_Selectivity_Equal
= 고정 0.1 선택도 (10 % 추측) :
-- the moment of doom
movsd xmm0,mmword ptr [sqllang!x_Selectivity_Equal
결과는 직교 곱에서 0.1 선택성입니다. 481577 * 94025 * 0.1 = 4528027742.5 (~ 4.52803e + 009).
다시 작성
문제가있는 조인이 주석 처리 되면 고정 선택성 "최후의 추측"을 피할 수 있기 때문에 더 나은 추정치가 생성됩니다 (핵심 정보는 1-M 조인에 의해 유지됨). COALESCE
결합 술어가 전혀 CE 친화적이 아니기 때문에 추정의 품질은 여전히 신뢰도가 낮습니다 . 수정 된 추정치는 적어도 인간에게는 더 합리적으로 보인다고 생각합니다.
쿼리를 외부 조인으로 작성하여 X_DETAIL_LINK
마지막 에 배치 하면 휴리스틱 재정렬은 쿼리를 최종 내부 조인으로 교체 할 수 X_LAST_TABLE
있습니다. 내부가 바로 옆에 참여 퍼팅 문제의 외부 "특별한"는 대부분 중복의 효과 대다 외부 올 조인 이후, 초기 재주문의 제한된 능력을 최종 견적을 개선 할 수있는 기회를 제공 가입 후 까다로운 선택도 추정 에 대한 COALESCE
. 다시 말하지만, 추정치는 고정 된 추측보다 조금 낫습니다. 그리고 아마도 법정에서 결정된 교차 검토를 견디지 못할 것입니다.
내부 및 외부 조인을 재정렬하는 것은 어렵고 시간이 많이 걸립니다 (2 단계 완전 최적화조차도 이론적 움직임의 제한된 하위 집합 만 시도합니다).
ISNULL
Max Vernon의 답변에 제안 된 중첩 은 구제 금융 고정 추측을 피하기 위해 관리되지만 최종 추정치는 불가능한 제로 행입니다 (정확도를 위해 한 행으로 향상). 이것은 계산이 가진 모든 통계적 기초에 대해 1 행의 고정 된 추측 일 수 있습니다.
0에서 481577 행 사이의 조인 카디널리티 추정이 예상됩니다.
이것은 물리적으로 다르지만 의미 적으로 동일한 서브 트리에서 카디널리티 추정이 다른 시간에 발생할 수 있음 (비용 기반 최적화 중)이 발생할 수 있음을 받아들 일지라도 합리적인 기대치입니다. (메모 그룹당) 최고. 계획 전체 일관성 보증이 없다고해서 개별 조인이 존중을 소중히 할 수 있어야한다는 의미는 아닙니다.
반면에 우리가 최후의 수단으로 추측 하면 희망은 이미 잃어 버렸으므로 왜 귀찮게합니까? 우리는 우리가 알고있는 모든 속임수를 시도하고 포기했습니다. 다른 것이 없다면, 최종 결과는이 쿼리를 컴파일하고 최적화하는 동안 모든 것이 CE 내부로 잘 들어 가지 않았다는 큰 경고 신호입니다.
MCVE를 시도했을 때 120+ CE ISNULL
는 원래 쿼리에 대해 제로 (= 1) 행 최종 추정치를 생성했습니다. 이는 내 생각에 맞지 않습니다.
실제 솔루션에는 아마도 설계 변경이 포함되어있어 COALESCE
또는 없이 또는 간단한 ISNULL
키 조인을 허용하고 쿼리 컴파일에 유용한 외래 키 및 기타 제약 조건이 가능합니다.
bigint
대신의decimal(18, 0)
혜택을 얻을 것이다 당신 : 영향을 미칠 수 1) 사용 8 바이트 대신에 모든 값 9, 2) 대신 압축 된 데이터 형식의 바이트 비교 데이터 형식을 사용합니다, 값을 비교할 때 CPU 시간.