因此,根据我所看到的WITH
使用方式以及MSDN 上的文档:
指定一个临时命名结果集,称为公用表表达式 (CTE)。
似乎WITH
是表的替代品#TEMP
。那是对的吗?
不。CTE——由——引入的——WITH
不要替换临时表,尽管在某些情况下,它们可以用于过去可能使用临时表的地方。
WITH
实际上只不过是一个派生表,不同之处在于它是在查询之前引入而不是内联,并被赋予一个别名,然后可以在整个查询中多次将其用作表。
派生表是一个完整的查询,在括号内,就像它是一个真实的表一样使用。视图和表值函数也被视为派生表,但我们关注的是内联定义的类型。这是一个例子:
SELECT
C.Name,
S.SalesTotal
FROM
dbo.Customer C
INNER JOIN (
SELECT
O.CustomerID,
SalesTotal = Sum(OrderTotal)
FROM
dbo.CustomerOrder O
GROUP BY
O.CustomerID
) S
ON C.CustomerID = S.CustomerID;
我们有一个完整的查询,它返回自己的行集(GROUP BY
查询)。通过将它放在括号内并为其分配一个别名S
,我们现在可以像使用表格一样使用它。我们可以将更多的表加入到这个表中。但是,我们只加入了这个表一次。
要将其转换为 CTE,我们进行了非常简单的更改:
WITH SalesTotals AS (
SELECT
O.CustomerID,
SalesTotal = Sum(OrderTotal)
FROM
dbo.CustomerOrder O
GROUP BY
O.CustomerID
)
SELECT
C.Name,
S.SalesTotal
FROM
dbo.Customer C
INNER JOIN SalesTotals S
ON C.CustomerID = S.CustomerID
-- and for an example of using the CTE twice:
INNER JOIN (
SELECT Avg(SalesTotal)
FROM SalesTotals
) A (AverageSalesTotal)
ON S.SalesTotal >= A.AverageSalesTotal;
现在,临时表是完全不同的动物。它与 CTE 或派生表有非常重要的区别:
Avg(SalesTotal)
在至少 2012 年之前的 SQL Server 版本中,计算将涉及SalesTotals
第二次执行聚合的完全独立的操作。虽然引擎可以实现 CTE 的结果,但到目前为止 SQL Server 还没有做到这一点。值得注意的是,Oracle 等其他 DBMS 可能会实现 CTE 的结果。无论如何,您应该知道这种双重查询可能(当然!)严重的性能影响。最后,CTE 可以做一些临时表不能做的事情:它可以是递归的。在 Oracle 中,这是通过 表示的CONNECT BY
,而在 SQL Server 中,它是通过UNION ALL SELECT
CTE 内部的 a 来完成的,该 CTE 允许引用 CTE 自己的别名。
小心 CTE——它们是一个很好的抽象,但仅此而已,你可能会遇到严重的麻烦。生成一百万行可以使用递归 CTE 一次一行来完成,但这是最糟糕的方法,可能是一百倍或更多。
SQL Server 2005 和更高版本中还有另一种特殊的临时表,称为“表变量”,它非常类似于临时表(并且在 tempdb 中保持完全相同),但有一些值得注意的例外:
今天,SQL 优化器在选择出色的执行计划方面做得更好,但是当连接超过 10 个表时,尤其是对于一些大型表和视图并且需要使用多个过滤器时,它通常不会以最佳方式执行。我仍然发现没有什么比使用#TEMP 表和在将它们连接在一起之前将查询分解成更小的子集更快的了。注意:我很少发现向#TEMP 表添加索引可以提高性能。
不,这是不正确的。它们都是独立的功能,每个都有各自的用途。
例如,CTE 适用于少量数据,而临时表通常更适合较大的数据集。临时表可以被索引并提高它们的性能,而 CTE 不能。
我会花一点时间阅读 MSDN 文档并查看您将使用其中一个或另一个的特定实例