Sql server 2008 r2 多次执行CTE

Sql server 2008 r2 多次执行CTE,sql-server-2008-r2,common-table-expression,Sql Server 2008 R2,Common Table Expression,我有这样的结构: 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(GE

我有这样的结构:

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
中单独运行代码,需要3秒;但是完整的脚本只是不断地运行

如果我从一个
CTE
移动并使用一个索引临时表,那么它将在4秒内运行

我假设发生的情况是,
CTE
正在对
tb\u otherData
中的每个数据记录执行,因此可能需要2000条记录,2000 x 3sec……太长了

临时表解决方案很好,但出于兴趣,是否有办法更改
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
              );

请尝试使用此查询,而不是使用具有以下内容的子查询:

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
如果
DateKey
来自
WHData.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

在这种情况下,CTE只是语法上的糖分——它们让你觉得它们只评估了一次,但事实往往并非如此。您是否在寻找解释或解决方法(例如,在没有CTE和临时表的情况下编写查询)?@AaronBertrand实际上我刚刚测试过,如果切换到子查询,执行计划完全相同。我真的想知道我是否可以保留CTE,但也许有一个技巧我错过了,使它更快?p、 前几天,美国与一位名叫“no”的“horse”进行了一场略显激烈的讨论,他告诉我应该将
x这样的列别名为mycolumn
,但也提到了你的名字——我以为你是学校的
mycolumn=x
?是的,CTE只是编写子查询的另一种方式。如果我们不讨论递归,它们可能会进行相同的优化。是的,我是
alias=column
,但这只是一种偏好,不值得争论。我会反对人们使用
列作为“别名”
'alias'=column
,但只是为了摆脱那些令人困惑和不推荐使用的愚蠢的字符串分隔符;出于某种原因,它要快得多——使用LOJ时的执行计划中没有嵌套循环;也许这就是好处。如果可能的话,您应该避免嵌套子查询和使用联接的子查询中的
。@valex为什么?在许多情况下,EXISTS/notexists的性能优于join(对于内部联接和不可为null的列,In/EXISTS可以生成完全相同的计划)。但你应该经常测试,而不是一概而论。