SQL Server 2012 에서 800 밀리 초로 실행 되고 SQL Server 2014에서 약 170 초가 걸리는 쿼리가 있습니다. 나는 이것을 Row Count Spool
운영자 의 열악한 카디널리티 추정치로 좁혔다 고 생각합니다 . 스풀 연산자 (예 : here 및 here ) 에 대해 약간 읽었 지만 여전히 몇 가지 사항을 이해하는 데 어려움이 있습니다.
- 이 쿼리에
Row Count Spool
연산자 가 필요한 이유는 무엇 입니까? 정확성이 필요하다고 생각하지 않으므로 특정 최적화를 제공하려고합니까? - SQL Server가
Row Count Spool
연산자에 대한 조인이 모든 행을 제거 한다고 추정하는 이유는 무엇 입니까? - SQL Server 2014의 버그입니까? 그렇다면 Connect에 제출하겠습니다. 그러나 먼저 더 깊이 이해하고 싶습니다.
참고 : LEFT JOIN
SQL Server 2012 및 SQL Server 2014 모두에서 허용 가능한 성능을 달성하기 위해 쿼리를 테이블 로 다시 작성 하거나 인덱스를 테이블에 추가 할 수 있습니다. 따라서이 질문은이 특정 쿼리를 이해하는 것에 대한 자세한 내용과 그에 대한 자세한 내용은 검색어를 다르게 표현하는 방법
느린 쿼리
전체 테스트 스크립트는 이 Pastebin 을 참조하십시오 . 내가보고있는 특정 테스트 쿼리는 다음과 같습니다.
-- Prune any existing customers from the set of potential new customers
-- This query is much slower than expected in SQL Server 2014
SELECT *
FROM #potentialNewCustomers -- 10K rows
WHERE cust_nbr NOT IN (
SELECT cust_nbr
FROM #existingCustomers -- 1MM rows
)
SQL Server 2014 : 예상 쿼리 계획
SQL Server는 믿고 Left Anti Semi Join
받는 사람은 Row Count Spool
한 행으로 만 개 행을 필터링합니다. 이러한 이유로 LOOP JOIN
이후 조인에 대한를 선택합니다 #existingCustomers
.
SQL Server 2014 : 실제 쿼리 계획
예상대로 (SQL Server를 제외한 모든 사람이) Row Count Spool
행을 제거하지 않았습니다. 따라서 SQL Server가 한 번만 반복 될 것으로 예상되는 경우 10,000 회 반복합니다.
SQL Server 2012 : 예상 쿼리 계획
SQL Server 2012 (또는 OPTION (QUERYTRACEON 9481)
SQL Server 2014)를 사용하는 Row Count Spool
경우 예상 행 수를 줄이고 해시 조인을 선택하면 훨씬 더 나은 계획을 얻을 수 있습니다.
왼쪽 가입 재 작성
참고로 다음은 모든 SQL Server 2012, 2014 및 2016에서 우수한 성능을 달성하기 위해 쿼리를 다시 작성할 수있는 방법입니다. 그러나 여전히 위 쿼리의 특정 동작 및 쿼리 여부에 관심이 있습니다. 새로운 SQL Server 2014 Cardinality Estimator의 버그입니다.
-- Re-writing with LEFT JOIN yields much better performance in 2012/2014/2016
SELECT n.*
FROM #potentialNewCustomers n
LEFT JOIN (SELECT 1 AS test, cust_nbr FROM #existingCustomers) c
ON c.cust_nbr = n.cust_nbr
WHERE c.test IS NULL