sql - SQL Server 2005 中 CTE 的评估

标签 sql sql-server sql-server-2005 common-table-expression temp-tables

我有一个关于 MS SQL 如何评估 CTE 内的函数的问题。几次搜索没有找到与此问题相关的任何结果,但如果这是常识并且我只是落后于潮流,我深表歉意。这不是第一次了:-)

这个查询是我实际正在做的事情的简化(并且显然不太动态)版本,但它确实展示了我遇到的问题。它看起来像这样:

CREATE TABLE #EmployeePool(EmployeeID int, EmployeeRank int);

INSERT INTO #EmployeePool(EmployeeID, EmployeeRank)
  SELECT 42, 1
  UNION ALL 
  SELECT 43, 2;

DECLARE @NumEmployees int;
SELECT @NumEmployees  = COUNT(*) FROM #EmployeePool;

WITH RandomizedCustomers AS (
  SELECT CAST(c.Criteria AS int) AS CustomerID,
         dbo.fnUtil_Random(@NumEmployees) AS RandomRank
    FROM dbo.fnUtil_ParseCriteria(@CustomerIDs, 'int') c)
SELECT rc.CustomerID,
       ep.EmployeeID
  FROM RandomizedCustomers rc
  JOIN #EmployeePool ep ON ep.EmployeeRank = rc.RandomRank;

DROP TABLE #EmployeePool;

对于上述所有执行,可以假设以下内容:

  • dbo.fnUtil_Random() 的结果始终是一个大于零且小于或等于传入参数的 int 值。因为上面使用 @ 调用它NumEmployees 的值为 2,该函数的计算结果始终为 1 或 2。

  • dbo.fnUtil_ParseCriteria(@CustomerIDs, 'int') 的结果生成一个单列单行表,其中包含基本类型为 'int' 的 sql_variant值为 219935。

鉴于上述假设,上面表达式的结果应该始终生成一个包含一条记录(CustomerID 和 EmployeeID)的两列表,这是有道理的(无论如何,对我来说)。 CustomerID 应始终为 int 值 219935,EmployeeID 应为 42 或 43。

但是,情况并非总是如此。有时我会得到预期的单曲记录。有时我会得到两条记录(每个 EmployeeID 一条),还有一些时候我没有得到任何记录。但是,如果我用真正的临时表替换 RandomizedCustomers CTE,问题就会完全消失。

每次我认为我对这种行为有一个解释时,结果证明它没有意义或不可能,所以我实际上无法解释为什么会发生这种情况。由于当我用临时表替换 CTE 时不会发生问题,因此我只能假设它与在连接到该 CTE 期间评估 CTE 内的函数有关。你们有什么理论吗?

最佳答案

SQL Server 的优化器可以自由决定是否重新评估CTE

例如,这个查询:

WITH    q AS
        (
        SELECT  NEWID() AS n
        )
SELECT  *
FROM    q
UNION ALL
SELECT  *
FROM    q

将生成两个不同的 NEWID(),但是,如果您使用缓存的 XML 计划将 CTE 包装到 >Eager Spool操作,记录将是相同的。

关于sql - SQL Server 2005 中 CTE 的评估,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2524072/

相关文章:

mysql - 如何为不同类型的用户制作出价表结构

sql - 如何引用 WHERE 子句中计算的另一个字段?

mysql - 按所有枚举值分组而不指定枚举值

SQL Server 查询以查找成员注册的年数

c# - MultipleActiveResultSets=True 或多个连接?

PHP MYSQL 将 AUTO INCREMENT 设置为 MAX + 1

sql-server - 如何查找过去一年内存储过程的最后执行时间?

c# - 如何确定 Sql server 中的公共(public)假期?

java - 如何防止Hibernate公式注释在保留字前添加表名?

sql-server - StackOverflow 导入错误 : LOB beyond 2, 147,483,647 字节?