2013-01-31 2 views
1

나는이 구조를 가지고 : 나는 분리에 CTE에서 코드를 실행하면 3 초 소요CTE 실행 여러 번

WITH my_cte 
    AS 
    (
    SELECT y.name 
    FROM 
     WHData.dbo.vw_data x 
     INNER JOIN WHData.dbo.vw_DimNames y 
       ON x.nameKey = y.CasinoKey 
    WHERE DateKey >= CONVERT(CHAR(8),DATEADD(mm,-2,GETDATE() - DAY(GETDATE())) + 1,112)--two complete months ago  
    GROUP BY y.name 
    ) 
SELECT * 
FROM WHAnalysis.dbo.tb_otherData a 
WHERE NOT EXISTS 
       (
      SELECT 1 
      FROM my_cte b 
      WHERE b.name = a.name 
      ); 

을; 하지만 전체 스크립트가 실행되고 실행됩니다.

CTE에서 벗어나 인덱스 된 임시 테이블을 사용하면 모두 4 초 후에 실행됩니다.

내가 생각하는 것은 CTEtb_otherData에있는 데이터의 각 레코드에 대해 실행 중이므로 2,000 레코드가 있으므로 아마 걸릴 것입니다. 2000 x 3 초 .... 너무 오래!

임시 테이블 솔루션은 문제가되지 않지만 CTE 코드를 변경하여 신속하게 실행할 수있는 방법이 있습니까? 일부 누락 된 CTE 트릭이 있습니까? 나는 좋은 구식 하위 쿼리로 전환하면


는 실행 계획은 절대적으로 동일

편집 :

SELECT * 
FROM WHAnalysis.dbo.tb_otherData a 
WHERE name not in 
     (
      SELECT y.name 
      FROM 
      WHData.dbo.vw_data x 
      INNER JOIN WHData.dbo.vw_DimNames y 
      ON x.nameKey = y.CasinoKey 
      WHERE DateKey >= CONVERT(CHAR(8),DATEADD(mm,-2,GETDATE() - DAY(GETDATE())) + 1,112)--two complete months ago 
       GROUP BY y.name 
      ); 
+0

CTE는이 경우 단지 문법 설탕 - 그들은 당신이 그들이 한 번만 평가하고 생각하게하지만 종종이 아니다. 설명이나 임시 해결책 (예 : CTE * 및 *없이 임시 테이블없이 쿼리 작성)을 찾으십니까? –

+0

@AaronBertrand 실제로 하위 테스트로 전환하면 실제로 테스트 한 결과 실행 계획이 ** 똑같습니다 **. 실제로 CTE를 유지할 수 있을지 궁금해했지만 어쩌면 빠르기 때문에 빠져 나간 트릭이 있었을까요? 추신. 며칠 전 a_horse_with_no_name과 약간의 토론을 가졌습니다. 다른 날에는'x를 mycolumn과 같은 별칭으로 지정해야하지만 이름도 언급해야합니다. '나는 당신이'mycolumn = x'라는 학교에 속한 줄 알았습니까? – whytheq

+1

예, CTE는 하위 쿼리를 작성하는 다른 방법 일뿐입니다. 재귀 적으로 이야기하지 않는다면 동일하게 최적화 될 것입니다. 그리고 네, 저는'alias = column'입니다. 그러나 그것은 단지 기본 설정 일 뿐이며 논쟁 할 가치가 없습니다. 나는 'alias' 'OR' 'alias'= column'과 같은 컬럼을 사용하는 사람들에 대해 논쟁 할 것이지만, 혼란스럽고 사용되지 않는 어리석은 문자열 구분자를 없애기 위해서만 논할 것이다. –

답변

2

시도 대신에 하위 쿼리를 사용하는이 쿼리를 사용하는 존재하는 경우 :

SELECT a. * 
FROM WHAnalysis.dbo.tb_otherData a 
LEFT JOIN 
( SELECT y.name as name 
    FROM WHData.dbo.vw_data x 
     INNER JOIN WHData.dbo.vw_DimNames y 
       ON x.nameKey = y.CasinoKey 
     WHERE DateKey >= 
      CONVERT(CHAR(8),DATEADD(mm,-2,GETDATE() - DAY(GETDATE())) + 1,112)  
) b on a.name=b.name 
WHERE b.name is null 

DateKeyWHData.dbo.vw_data에서입니다 다음은 다음과 같습니다

SELECT a. * 
FROM WHAnalysis.dbo.tb_otherData a 
LEFT JOIN WHData.dbo.vw_DimNames y on a.name=y.name 
LEFT JOIN WHData.dbo.vw_data x 
    on y.CasinoKey= x.nameKey 
     and (
      x.DateKey >= 
      CONVERT(CHAR(8),DATEADD(mm,-2,GETDATE() - DAY(GETDATE())) + 1,112) 
     ) 
WHERE x.nameKey is null 
+0

+1이 L.O.J가 자리하고있다. 어떤 이유로 그것은 훨씬 더 빠릅니다 - LOJ를 사용할 때 실행 계획에는 중첩 된 루프가 없습니다. 어쩌면 그것은 이득입니다. – whytheq

+0

가능한 경우 중첩 된 서브 쿼리와 JOIN을 대신 사용하는'IN' 서브 쿼리를 피해야합니다. – valex

+0

@valex 왜? 많은 경우 EXISTS/NOT EXISTS가 JOIN보다 성능이 뛰어납니다 (내부 조인과 null이 아닌 열의 경우 IN/EXISTS가 정확히 동일한 계획을 생성 할 수 있음). [다음은 내가 존재하지 않는 블로그 게시물입니다] (http://sqlperformance.com/left-anti-semi-join). 그러나 전반적인 일반화보다는 항상 테스트해야합니다. –