2

這裏是運行和運行原始查詢:在刪除使用CTE不執行

;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

這裏的具體答案取決於如果您不在第二個示例中創建聚集索引時這些執行方式有多不同。除此之外,如果您搜索「臨時表與表變量與cte」或類似的東西,則有很多信息可用。 –

+0

@ 010001100110000101110010011010,表變量也可以寫入tempdb。 –

回答

3

CTE在使用時解決。這意味着如果您在查詢中使用它兩次,它可能會解決兩次。 CTE做並不總是得到解決一次並緩存在內存中。 SQL Server可以自由地執行查詢,因爲它認爲合適。

就你而言,它可能比這更糟 - 因爲你已經在EXISTS子句中使用它作爲相關的子查詢,這是一個逐行操作。這可能意味着計劃結果在CTE被解決了#permissions表的EACH ROW!那很可能是所有時間都會去的地方。在SSMS中顯示執行計劃(Ctrl-L)是你的朋友。

檢查此SQLFiddle,這表明沒有任何GUID是相同的,即使CTE只創建3行。事實上,我們得到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

但他們並不總是解決兩次。另一個[SQL-Fiddle](http://sqlfiddle.com/#!3/d41d8/5577)(用40而不是3)與不同的執行計劃(而不是2x40x40不同的GUID)。 –

+0

是的,編輯了答案。我沒有提到它不這麼做的原因,因爲我正在準備解決OP的問題。 – RichardTheKiwi

+0

+1優秀答案 – whytheq