tempdb 이벤트에 유출이 발생하면 (느린 쿼리 발생) 종종 특정 조인에 대해 행 추정이 중단되는 것을 알 수 있습니다. 병합 및 해시 조인으로 유출 이벤트가 발생하는 것을 보았으며 종종 런타임을 3 배에서 10 배로 증가시킵니다. 이 질문은 유출 사건의 가능성을 줄일 것이라는 가정 하에서 행 추정치를 개선하는 방법에 관한 것입니다.
실제 행 수 40k.
이 쿼리의 경우 계획에 잘못된 행 추정치 (11.3 행)가 표시됩니다.
select Value
from Oav.ValueArray
where ObjectId = (select convert(bigint, Value) NodeId
from Oav.ValueArray
where PropertyId = 3331
and ObjectId = 3540233
and Sequence = 2)
and PropertyId = 2840
option (recompile);
이 쿼리의 경우 계획에 양호한 행 예상치 (56k 행)가 표시됩니다.
declare @a bigint = (select convert(bigint, Value) NodeId
from Oav.ValueArray
where PropertyId = 3331
and ObjectId = 3540233
and Sequence = 2);
select Value
from Oav.ValueArray
where ObjectId = @a
and PropertyId = 2840
option (recompile);
첫 번째 경우에 대한 행 추정치를 향상시키기 위해 통계 또는 힌트를 추가 할 수 있습니까? 특정 필터 값 (속성 = 2840)으로 통계를 추가하려고 시도했지만 조합을 올바르게 얻을 수 없거나 컴파일 타임에 ObjectId를 알 수 없으므로 모든 ObjectId에 대한 평균을 선택했을 수 있으므로 무시됩니다.
프로브 쿼리를 먼저 수행 한 다음이를 사용하여 행 추정값을 결정하거나 맹목적으로 비행해야하는 모드가 있습니까?
이 특정 속성은 몇 가지 개체에 많은 값 (40k)이 있고 대부분의 경우 0입니다. 주어진 조인에 대해 예상되는 최대 행 수를 지정할 수있는 힌트에 만족합니다. 일부 매개 변수는 조인의 일부로 동적으로 결정되거나 뷰 내에 더 잘 배치 될 수 있기 때문에 일반적으로 귀찮은 문제입니다 (변수를 지원하지 않음).
tempdb 로의 유출 가능성을 최소화하기 위해 조정할 수있는 매개 변수가 있습니까 (예 : 쿼리 당 최소 메모리)? 강력한 계획은 추정에 영향을 미치지 않았습니다.
편집 2013.11.06 : 의견 및 추가 정보에 대한 답변 :
쿼리 계획 이미지는 다음과 같습니다. 경고는 convert ()의 카디널리티 / 검색 술어에 관한 것입니다.
@Aaron Bertrand의 의견에 따라 테스트로 convert ()를 바꾸려고했습니다.
create table Oav.SeekObject (
LookupId bigint not null primary key,
ObjectId bigint not null
);
insert into Oav.SeekObject (
LookupId, ObjectId
) VALUES (
1, 3540233
)
select Value
from Oav.ValueArray
where ObjectId = (select ObjectId
from Oav.SeekObject
where LookupId = 1)
and PropertyId = 2840
option (recompile);
이상하지만 성공적인 관심 지점으로, 조회를 단축시킬 수있었습니다.
select Value
from Oav.ValueArray
where ObjectId = (select ObjectId
from Oav.ValueArray
where PropertyId = 2840
and ObjectId = 3540233
and Sequence = 2)
and PropertyId = 2840
option (recompile);
이 두 가지 모두 올바른 키 조회를 나열하지만 첫 번째 키만 ObjectId의 "출력"을 나열합니다. 두 번째가 실제로 단락되었음을 나타냅니다.
누군가 행 예측을 돕기 위해 단일 행 프로브가 수행되는지 여부를 확인할 수 있습니까? 단일 행 PK 조회가 히스토그램에 대한 조회 정확도를 크게 향상시킬 수있는 경우 (특히 유출 가능성 또는 기록이있는 경우) 히스토그램 추정치로만 최적화를 제한하는 것은 잘못된 것 같습니다. 실제 쿼리에 이러한 하위 조인 중 10 개가있는 경우 이상적으로 병렬로 발생합니다.
참고로, sql_variant는 기본 유형 (SQL_VARIANT_PROPERTY = BaseType)을 필드 자체에 저장하기 때문에 "직접"변환 할 수있는 한 (예 : 문자열이 아닌 10 진수가 아니라 int 인 경우) convert ()가 거의 비용이 들지 않을 것으로 예상됩니다. int 또는 bigt to int). 컴파일 타임에는 알려지지 않았지만 사용자가 알 수 있으므로 sql_variants에 대한 "AssumeType (type, ...)"함수를 사용하면 더 투명하게 처리 할 수 있습니다.
declare @a bigint =
당신이 한 것처럼 쿼리를 나누는 것이 자연스러운 해결책 인 것 같습니다. 왜 받아 들일 수 없습니까?
CONVERT()
. 이것은 대부분 효율적이지 않은 방법입니다. 이 특정 항목에서는 변환해야 할 값이 하나뿐이므로 문제는 아니지만 테이블에 어떤 색인이 있습니까? EAV 디자인은 일반적으로 적절한 인덱싱 (일반적으로 좁은 테이블에 많은 인덱스가 있음)만으로도 성능이 우수합니다.