외부 매개 변수화 된 'where'절이있는 뷰에서 호출 될 때 창 함수로 인해 실행 계획이 끔찍하다


10

오래 전에이 문제가 있었는데 나에게 맞는 해결 방법을 발견하고 잊어 버렸습니다.

그러나 이제 그에 대한 질문 이 있으므로이 문제를 기꺼이 제기하겠습니다.

몇 가지 테이블을 매우 간단한 방식으로 정렬하는 뷰가 있습니다 (오더 + 오더 라인).

where절 없이 쿼리 하면 뷰는 수백만 줄을 반환합니다.
그러나 아무도 그렇게 그렇게 부르지 않습니다. 일반적인 검색어는

select * from that_nasty_view where order_number = 123456;

이렇게하면 5m 중 약 10 개의 레코드가 반환됩니다.

중요한 것은 : 뷰에는 윈도우 함수가 포함되어 rank()있으며, 뷰는 항상 쿼리가 사용되는 필드로 정확하게 분할됩니다.

rank() over (partition by order_number order by detail_line_number)

이제이 뷰가 쿼리 문자열에서 리터럴 매개 변수로 쿼리되면 위와 같이 정확하게 행을 리턴합니다. 실행 계획은 괜찮습니다.

  • 인덱스는 인덱스를 사용하여 두 테이블 모두에서 검색 order_number합니다 (10 개의 행을 반환 함).
  • 작은 결과를 반환하는 창을 계산합니다.
  • 선택 중입니다.

그러나 뷰가 매개 변수화 된 방식으로 호출되면 상황이 악화됩니다.

  • Index scan인덱스를 무시하고 모든 테이블에. 5m 행을 반환합니다.
  • 큰 조인.
  • 모든 partitions에 대한 창 계산 (약 500k 창).
  • Filter 5m에서 10 개의 행을 가져옵니다.
  • 고르다

이는 매개 변수가 관련된 모든 경우에 발생합니다. SSMS 일 수 있습니다.

declare @order_number int = 123456;
select * from that_nasty_view where order_number = @order_number;

Excel과 같은 ODBC 클라이언트 일 수 있습니다.

select * from that_nasty_view where order_number = ?

또는 SQL 연결이 아닌 매개 변수를 사용하는 다른 클라이언트 일 수 있습니다.

창 함수가보기에서 제거되면 매개 변수로 조회되는지 여부에 관계없이 완벽하게 빠르게 실행됩니다.

내 해결 방법은 문제가되는 기능을 제거하고 나중에 다시 적용하는 것이 었습니다.

그러나 무엇을 제공합니까? SQL Server 2008에서 창 기능을 처리하는 방식이 실제로 버그입니까?


order_number는 기본 키입니까? 열의 데이터 유형과 매개 변수가 일치합니까?
— gbn

order_number기본 키가 아닙니다. 그것은이다 int not null두 테이블에에 클러스터되지 않은 인덱스.
— GSerg

5
SQL Server 2005에는 이 영역에서 술어 푸시 와 관련된 문제가있었습니다 . 나는 그들이 지금 고쳐 졌다고 생각했다. BTW TSQL 예제는 매개 변수가 아닌 변수를 사용합니다. 추가 않는 OPTION (RECOMPILE)도움을?
— Martin Smith

1
@ GSerg-필터가 잘못된 계획에서 필터에 약 5 백만 개의 행이 있고 실제와 일치하는 것으로 추정되는 10 개의 행이 있습니까? 그렇다면 술어 푸시 문제가 여전히 완전히 해결되지 않은 것일 수 있습니다.
— Martin Smith

답변:


5

이것은 오래 지속되는 문제로, 한 형태 또는 다른 형태로 재 포장을 계속하고 여전히 SQL Server 2012에 있습니다.

그것을 논의하는 일부 게시물은

2012 년까지의 모든 현재 SQL Server 버전 option(recompile)은 사용 된 경우 (2008+ 인 경우 )를 제외하고 매개 변수화 된 술어에 대해 시퀀스 프로젝트를지나 파티션 그룹의 필터를 푸시 할 수 없습니다 .

recompile힌트에 대한 대안 은 @ a1ex07에서 제안한대로 매개 변수화 된 인라인 TVF를 사용하도록 쿼리를 다시 작성하는 것입니다.


SQL Server 2014에서도 마찬가지
— Guillaume86

3

뷰를 테이블 반환 udf로 바꾸려고합니다. 그렇게하면 먼저 레코드를 필터링 한 다음 창 기능을 적용합니다. 여러 전달할 수 있도록이 기능은 테이블 매개 변수를 수용 할 수 order_number그것으로


또 다른 해결 방법입니다. 모든 클라이언트가 테이블 반환 함수를 사용할 수있는 것은 아니기 때문에 그렇게 할 수 없었습니다.
— GSerg

왜? 100 % 확신 할 수는 없지만 쿼리를 약간 변경하면됩니다SELECT * FROM my_funct(12345)
— a1ex07

요구 사항 중 하나는 Excel을 사용하는 최종 사용자 (즉, MS Query)가 쿼리를 사용할 수 있어야한다는 것입니다. MS Query는 적어도 2003 년까지의 버전에서는이를 수행 할 수 없습니다.
— GSerg

it will filter records first, and then apply window function부정확하다. 결정 론적 명령은 없다
— Remus Rusanu
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.