여기

2

을 실행하지 않는 실행 및 실행 원래 쿼리입니다 :여기

;WITH includedCs_cte 
    AS 
    (
    SELECT 
      x.PKey, 
      x.OKey, 
      y.CKey 
    FROM 
      #Permissions x 
      JOIN WHDATA.dbo.tb_DimC y 
        ON 
        x.PKey = y.PKey AND 
        x.OKey = y.OKey 
     ) 
, b_cte 
    AS 
    (
    SELECT 
      i.OKey, 
      i.PKey 
    FROM 
       WHData.dbo.vw_FactCX b 
       INNER JOIN includedCs_cte i 
         ON 
         b.PKey = i.PKey AND 
         b.PlayCKey = i.CKey 
    WHERE b.DateKey >= @myLAST28DAYS 
    GROUP BY 
      i.OKey, 
      i.PKey 
    ) 
, POK_cte 
    AS 
    (
    SELECT 
      i.OKey, 
      i.PKey 
    FROM 
       WHData.dbo.vw_FactCY b 
       INNER JOIN includedCs_cte i 
         ON 
         b.PKey = i.PKey AND 
         b.PlayCKey = i.CKey 
    WHERE b.DateKey >= @myLAST28DAYS 
    GROUP BY 
      i.OKey, 
      i.PKey 
    ) 
, includedOKeys 
    AS 
    (
    SELECT * 
    FROM b_cte 
    UNION 
    SELECT * FROM POK_cte 
    ) 
DELETE FROM #Permissions 
FROM #Permissions p 
WHERE NOT EXISTS 
        (
        SELECT 1 
        FROM includedOKeys x 
        WHERE 
          p.PKey = x.PKey AND 
          p.OKey = x.OKey  
        ) 

다음은 10 초 미만에서 실행 내가 아래에 위의 내용을 변경하는 경우는. 왜 이러한 실행 방식이 다릅니 까?

;WITH includedCs_cte 
    AS 
    (
    SELECT 
      x.PKey, 
      x.OKey, 
      y.CKey 
    FROM 
      #Permissions x 
      JOIN WHDATA.dbo.tb_DimC y 
        ON 
        x.PKey = y.PKey AND 
        x.OKey = y.OKey 
     ) 
, b_cte 
    AS 
    (
    SELECT 
      i.OKey, 
      i.PKey 
    FROM 
       WHData.dbo.vw_FactCX b 
       INNER JOIN includedCs_cte i 
         ON 
         b.PKey = i.PKey AND 
         b.PlayCKey = i.CKey 
    WHERE b.DateKey >= @myLAST28DAYS 
    GROUP BY 
      i.OKey, 
      i.PKey 
    ) 
, POK_cte 
    AS 
    (
    SELECT 
      i.OKey, 
      i.PKey 
    FROM 
       WHData.dbo.vw_FactCY b 
       INNER JOIN includedCs_cte i 
         ON 
         b.PKey = i.PKey AND 
         b.PlayCKey = i.CKey 
    WHERE b.DateKey >= @myLAST28DAYS 
    GROUP BY 
      i.OKey, 
      i.PKey 
    ) 
, includedOKeys 
    AS 
    (
    SELECT * 
    FROM b_cte 
    UNION 
    SELECT * FROM POK_cte 
    ) 
SELECT * 
INTO #includedOKeys 
FROM includedOKeys 
CREATE CLUSTERED INDEX ix_inclProdOper ON #includedOKeys(OKey, PKey) 

DELETE FROM #Permissions 
FROM #Permissions p 
WHERE NOT EXISTS 
     (
     SELECT 1 
     FROM #includedOKeys x 
     WHERE 
      p.PKey = x.PKey AND 
      p.OKey = x.OKey  
     ) 
+2

실행 계획은 신비를 나타낼 수 있으며 SQL은 변수 테이블을 CTE 용으로 메모리에 작성하기 때문에 두 번째 테이블에서 임시 테이블을 만들 수 있습니다. – Farfarak

+0

두 번째 예제에서 클러스터 된 인덱스를 만들지 않으면 이러한 차이점이 어떻게 다른지에 따라 다릅니다. 그 외에도 "임시 테이블 대 테이블 변수 대 테이블"또는 이와 유사한 것을 검색하면 많은 정보를 얻을 수 있습니다. –

+0

@ 010001100110000101110010011010이면 테이블 변수도 tempdb에 쓸 수 있습니다. –

답변

3

CTE는 사용시 해결됩니다. 즉, 쿼리에서 두 번 사용하면 두 번 해결 될 수 있습니다. 항상 CTE가 수행하지는 않습니다.은 한 번 해결되고 메모리에 캐시됩니다. SQL Server는 적합하다고 판단되는 쿼리를 자유롭게 실행할 수 있습니다.

경우에 따라 EXISTS 절 (행 단위 작업)에서 상관 된 하위 쿼리로 사용했기 때문에 이보다 더 좋지 않을 수 있습니다. 이는 계획에 따라 CTE가 각 행 #permissions 테이블로 해결된다는 것을 의미합니다. 그것은 항상 모든 시간이 갈 곳이 될 수 있습니다. SSMS의 실행 계획 표시 (Ctrl-L)는 귀하의 친구입니다.

확인하십시오. SQLFiddle을 확인하십시오. CTE에서 3 행만 생성하더라도 GUID 중 NONE이 동일하다는 것을 보여줍니다. 사실, 우리는 18 개의 다른 GUID를 얻습니다.

with cte(guid,other) as (
    select newid(),1 union all 
    select newid(),2 union all 
    select newid(),3) 
select a.guid, a.other, b.guid guidb, b.other otherb 
from cte a 
cross join cte b 
order by a.other, b.other; 
+0

그러나 항상 두 번 해결되는 것은 아닙니다. 다른 실행 계획 (2x40x40 다른 GUID가 아님)이있는 다른 [SQL-Fiddle] (http://sqlfiddle.com/#!3/d41d8/5577) (3 대신 40). –

+0

사실, 대답을 편집했습니다. 나는 그것이 OP의 쿼리에 무슨 일이 일어나고 있는지에 대한 해답을 제시하고 있기 때문에 어디에서 그렇게하지 않았는 지 언급하지 않았다. – RichardTheKiwi

+0

+1 우수 답변 – whytheq