sql-server - CTE 和临时表哪个性能更高?

标签 sql-server performance sql-server-2008 temp-tables common-table-expression

CTE临时表哪个性能更高?

最佳答案

这取决于。

首先

什么是通用表表达式?

(非递归)CTE 的处理方式与其他也可用作 SQL Server 中的内联表表达式的构造非常相似。派生表、 View 和内联表值函数。请注意,虽然 BOL 说 CTE“可以被认为是临时结果集”,但这纯粹是逻辑描述。通常,它本身并没有具体化。

什么是临时表?

这是存储在 tempdb 数据页上的行的集合。数据页可以部分或全部驻留在存储器中。此外,临时表可以被索引并具有列统计信息。

测试数据

CREATE TABLE T(A INT IDENTITY PRIMARY KEY, B INT , F CHAR(8000) NULL);

INSERT INTO T(B)
SELECT TOP (1000000)  0 + CAST(NEWID() AS BINARY(4))
FROM master..spt_values v1,
     master..spt_values v2;

示例 1

WITH CTE1 AS
(
SELECT A,
       ABS(B) AS Abs_B,
       F
FROM T
)
SELECT *
FROM CTE1
WHERE A = 780

Plan 1

请注意,上述计划中没有提及 CTE1。它只是直接访问基表并被视为相同

SELECT A,
       ABS(B) AS Abs_B,
       F
FROM   T
WHERE  A = 780 

通过将 CTE 物化到中间临时表中进行重写会产生巨大的反作用。

具体化 CTE 定义

SELECT A,
       ABS(B) AS Abs_B,
       F
FROM T

需要将大约 8GB 的​​数据复制到临时表中,然后仍然存在从中进行选择的开销。

示例 2

WITH CTE2
     AS (SELECT *,
                ROW_NUMBER() OVER (ORDER BY A) AS RN
         FROM   T
         WHERE  B % 100000 = 0)
SELECT *
FROM   CTE2 T1
       CROSS APPLY (SELECT TOP (1) *
                    FROM   CTE2 T2
                    WHERE  T2.A > T1.A
                    ORDER  BY T2.A) CA 

上面的示例在我的机器上大约需要 4 分钟。

1,000,000 个随机生成的值中只有 15 行与谓词匹配,但昂贵的表扫描发生了 16 次才能找到这些值。

enter image description here

这将是实现中间结果的良好候选。等效的临时表重写花费了 25 秒。

INSERT INTO #T
SELECT *,
       ROW_NUMBER() OVER (ORDER BY A) AS RN
FROM   T
WHERE  B % 100000 = 0

SELECT *
FROM   #T T1
       CROSS APPLY (SELECT TOP (1) *
                    FROM   #T T2
                    WHERE  T2.A > T1.A
                    ORDER  BY T2.A) CA 

With Plan

将查询的一部分中间具体化到临时表中有时会很有用,即使只计算一次 - 当它允许利用具体化结果的统计信息重新编译查询的其余部分时。 SQL Cat 文章 When To Break Down Complex Queries 中提供了这种方法的示例。 .

在某些情况下,SQL Server 将使用假脱机来缓存中间结果,例如的 CTE,并避免重新评估该子树。这在(迁移的)连接项 Provide a hint to force intermediate materialization of CTEs or derived tables 中进行了讨论。 。然而,没有对此创建统计信息,即使假脱机行数与估计值有很大不同,正在进行的执行计划也不可能动态适应响应(至少在当前版本中)。自适应查询计划可能在未来)。

关于sql-server - CTE 和临时表哪个性能更高?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/690465/

相关文章:

sql - Case 和 When 语句中的问题

sql-server - SQL Server 2000 : Invalid column name 'bar'

Java性能谜题: wrapper classes faster than primitive types?

sql-server - 在 Microsoft SQL Server 中删除并重新创建数据库

sql-server - SQL Server,误导性的 XLOCK 和优化

sql - 通过 SQL 使用 WHERE 子句查询 XML 子节点

SQL Server 计算给出了意外的结果

php - 我应该调用一个包含 SESSION 值的变量而不是在 PHP 中调用实际 session 吗?

python - python 的尾部。最佳性能实现

c# - 防止 SQL Server 数据库中重复记录的最佳方法是什么