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     
        )   
4

1 に答える 1

3

CTE は使用時に解決されます。これは、クエリで 2 回使用すると、2 回解決される可能性があることを意味します。CTE は常に一度解決されてメモリにキャッシュされるとは限りません。SQL Server は、必要に応じてクエリを自由に実行できます。

あなたの場合、行ごとの操作である EXISTS 句で相関サブクエリとして使用したため、それよりも悪い可能性があります。これはおそらく、#permissions テーブルの各行に対して CTE が解決されるという計画の結果になることを意味します! それは、常にどこに行くのかということです。SSMS での実行計画の表示 (Ctrl-L) は、ここでの友達です。

このSQLFiddleを確認すると、CTE が 3 行しか作成しないにもかかわらず、GUID がどれも同じではないことが示されます。実際、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;
于 2012-10-25T14:29:16.217 に答える