오늘 회의가 너무 많았지 만 두뇌가 여전히 남아 있다고 생각합니다. 나는 다음과 같은 신비 건너 온 일부 쿼리의 성능을 개선하기위한 내 노력의 일환으로 (테이블 이름과 필드 의역) : 당신이 볼 수 있듯이SQL Server 쿼리 성능 미스터리
SELECT X.ADId FROM
(
SELECT DISTINCT A.ADId
FROM P WITH (NOLOCK)
INNER JOIN A WITH (NOLOCK) ON (P.ID = A.PId)
INNER JOIN dbo.fn_A(16) AS VD ON (VD.DId = A.ADId)
LEFT JOIN DPR ON (LDID = A.ADId)
WHERE ((A.ADId = 1) OR ((HDId IS NOT NULL) AND (HDId = 1))) AND
(P.PS NOT IN(5,7)) AND (A.ASP IN (2, 3))
) X
WHERE (dbo.fn_B(X.ADId, 16) = 1)
는 내부 쿼리의 내용은 대부분 관련이 있습니다. 처음에는 모든 레코드에 대해 ADId에 중복 값이 포함 된 fn_B()가 발생하지 않도록하고 싶었 기 때문에 SELECT DISTINCT를 사용하여 내부적으로 개별 레코드를 필터링했습니다. 소리가 합리적입니까? 여기
는내부 쿼리 (지정된 매개 변수에 대한) 레코드를 반환 ... 신비를 시작합니다. "WHERE fn_B() = 1"을 주석 처리하면 쿼리가 0 시간에 실행되고 결과가 반환되지 않습니다. 다시 입력하면 쿼리에 6-10 초가 걸리고 결과가 반환되지 않습니다.
이것은 내 상식을 뛰어 넘는 것처럼 보입니다. 내 공통 SQL 의미 :-) 내부 쿼리가 데이터를 반환하지 않으면 외부 조건이 올바르게 평가되지 않아야합니까?
물론 실제 실행 계획을 확인하고 저장 한 다음 매우 신중하게 비교했습니다. 그것들은 99 % 동일하며, 특별한 통지가 없기 때문에 생각합니다.
일부 CTE를 속이고 첫 번째 CTE에서 쿼리 결과를 얻은 다음 레코드를 필터링하지 않도록 보장 된 몇 가지 조건이있는 두 번째 CTE로 전달한 다음 모든 CTE 외부에서 fn_B() 호출을 평가하지만 그 행동은 정확히 동일했다.
이전 쿼리 (같은 값으로 fn_B()를 여러 번 호출 할 수 있음)를 사용하는 것과 같은 다른 변형도 동일한 동작을합니다. 조건을 제거하면 제로 시간에 기록이 없습니다. 다시 넣으면 10 초 안에 아무런 기록도 남기지 않습니다.
아무도 아이디어가 없습니까?
PS1 :-) 시간에 대한
감사합니다 : 나는 간단한 쿼리를 사용하여 tempdb에의 상황을 재현하려하지만 난 그렇게 할 수 없었다. 그것은 내 실제 테이블에서만 발생합니다. PS2 :이 쿼리는 다른 함수 내에서 호출되므로 결과를 임시 테이블에 저장 한 다음 추가로 필터링하는 것도 문제가되지 않습니다.
대부분의 사람들은 옵티마이 저가 이상한 방식으로 내용을 재 배열한다는 것을 이미 알고 있다고 생각합니다. 그러나 때때로 쿼리는 프로그래머가 무슨 일이 일어나는지를 담당하는 방식으로 작성됩니다. 내가 두 개의 SELECT DISCTINCT를 실행 한 다음에 조인하면, 나는 대략 무슨 일이 일어날 지 확신합니다. 어쨌든, 오늘 내부 질의가 실제로 데이터를 가져 오는 호출이나 fn_B()를 더미 함수로 대체하는 호출을 시도해보고 동작이 어떻게 바뀌는 지 살펴 보겠습니다. –
그렇게 생각 하겠지만 예외는 많습니다. 최적화 프로그램이 완벽하지 않습니다. 오늘 Hugo의 블로그 게시물과 버그 보고서를 읽었습니까? http://sqlblog.com/blogs/hugo_kornelis/archive/2012/05/04/the-curious-case-of-the-optimizer-that-doesn-t.aspx 필자는 몇 가지 사례를 보았다. 옵티마이 저가 쿼리를 개별 쿼리로 나눌 것으로 예상되는 동작을 적용합니다. 위에서 제안한대로 시도 할 수있는 아이디어 일뿐입니다. –
추가 정보 나는 6 행을 반환 params와 내부 쿼리를 실행합니다. 제로. WHERE ==> 30 초를 추가하십시오. 나는이 ID들로 총 0 초간 fn (B)에 6 개의 명시 적 호출을했다. SQL Server는 SAME 5 테이블에서 Table Scans를 반복적으로 시작하여 (프로파일 러 로그에 약 100.000 개의 항목이 있음) SQL Server에서 다음을 수행합니다. 질문. 이 모든 테이블은 fn_B() 내부에 나타나며 원래 예제에서는 호출되지 않습니다. NOLOCK을 제거해도 아무런 차이가 없습니다. 그래서 뭔가 SQL 서버가 혼란 스럽다는 것을 알기 시작했습니다. –