Answers:
我会说它们是不同的概念,但说“粉笔和奶酪”并不过分。
临时表适合重复使用或对一组数据执行多次处理。
CTE可用于递归或简单地提高可读性。
而且,就像视图或内联表值函数一样,也可以将其视为要在主查询中扩展的宏。
临时表是另一个具有范围相关规则的表
我已经在其中同时使用了procs和表变量了
这取决于。
首先
什么是通用表表达式?
(非递归)CTE与在SQL Server中也可用作内联表表达式的其他构造非常相似。派生表,视图和内联表值函数。请注意,尽管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
请注意,以上计划中没有提及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次才能找到这些谓词。
这对于实现中间结果将是一个很好的选择。等效的临时表重写花费了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
将查询的一部分具体化为临时表有时可能会有用,即使只对它进行一次评估-当它允许利用实现结果的统计信息重新编译其余查询时。SQL Cat文章“ 何时分解复杂查询”中提供了这种方法的示例。
在某些情况下,SQL Server将使用假脱机来缓存中间结果(例如CTE),并避免必须重新评估该子树。(迁移的)连接项中对此进行了讨论。提供提示以强制中间实现CTE或派生表。但是,不会为此创建任何统计信息,即使假脱机行的数量与估计的数量有很大出入,也无法使进行中的执行计划动态地响应以进行响应(至少在当前版本中。自适应查询计划在未来)。
CTE有其用途-当CTE中的数据较小且与递归表一样时,可读性会大大提高。但是,它的性能肯定不比表变量好,并且当处理一个非常大的表时,临时表的性能明显优于CTE。这是因为您无法在CTE上定义索引,并且当您有大量数据需要与另一个表联接时(CTE就像宏一样),您无法定义索引。如果将多个表连接在一起,每个表中都有数百万行的记录,则CTE的性能将显着低于临时表。
临时表始终在磁盘上-因此,只要您的CTE可以保存在内存中,它就可能会更快(也像表变量一样)。
但是话又说回来,如果CTE(或临时表变量)的数据负载太大,它也将存储在磁盘上,因此没有太大的好处。
通常,我更喜欢CTE而不是临时表,因为它在我使用后就消失了。我不需要考虑显式删除它或任何东西。
因此,最后没有明确的答案,但就个人而言,我更喜欢CTE而不是临时表。
CTE不会占用任何物理空间。这只是我们可以使用联接的结果集。
临时表是临时的。我们可以像创建普通表一样创建索引,约束,因为我们需要定义所有变量。
临时表的作用域仅在会话内。EX:打开两个SQL查询窗口
create table #temp(empid int,empname varchar)
insert into #temp
select 101,'xxx'
select * from #temp
在第一个窗口中运行此查询,然后在第二个窗口中运行以下查询,您可以找到区别。
select * from #temp
晚会晚了,但是...
我工作的环境非常受限,它支持某些供应商的产品并提供“增值”服务,例如报告。由于政策和合同的限制,通常不允许我使用单独的表/数据空间和/或创建永久代码的能力(根据应用程序的不同,它会变得更好一点)。
IOW,我通常不能开发存储过程,UDF或临时表等。我几乎必须通过我的应用程序界面来做所有事情(Crystal Reports-添加/链接表,设置带有CR的where子句等)。 )。节省的一个小好处是Crystal允许我使用COMMANDS(以及SQL表达式)。通过定义SQL命令,可以完成某些通过常规添加/链接表功能无法实现的工作。我通过它使用CTE,并且“远程”获得了很好的效果。CTE还可以帮助维护报表,而无需开发代码,而是交给DBA进行编译,加密,传输,安装,然后进行多级测试。我可以通过本地界面执行CTE。
使用带有CR的CTE的缺点是,每个报告都是独立的。必须为每个报告维护每个CTE。我可以在其中执行SP和UDF的地方,可以开发可以由多个报表使用的内容,仅需要链接到SP并传递参数,就好像您在处理常规表一样。CR并不是真正擅长将参数处理到SQL命令中,因此CR / CTE方面可能缺少。在这些情况下,我通常尝试定义CTE以返回足够的数据(但不返回ALL数据),然后使用CR中的记录选择功能对其进行切片和切块。
所以...我的投票是给CTE的(直到获得我的数据空间)。
根据我在SQL Server中的经验,我发现CTE胜过Temp表的情况之一
我只需要在存储过程中一次使用来自复杂查询的DataSet(〜100000)。
临时表在我的过程执行缓慢的SQL上造成了开销(因为临时表是在当前过程中存在于tempdb和Persist中的真实物化表)
另一方面,对于CTE,CTE仅在运行以下查询之前一直存在。因此,CTE是一种范围有限的方便的内存结构。默认情况下,CTE不使用tempdb。
在这种情况下,CTE可以真正帮助简化您的代码和胜过临时表。我曾经使用过2个CTE,例如
WITH CTE1(ID, Name, Display)
AS (SELECT ID,Name,Display from Table1 where <Some Condition>),
CTE2(ID,Name,<col3>) AS (SELECT ID, Name,<> FROM CTE1 INNER JOIN Table2 <Some Condition>)
SELECT CTE2.ID,CTE2.<col3>
FROM CTE2
GO