Rac*_*hel 183 sql-server cte
通用表表达式 (CTE) 和临时表有什么区别?我什么时候应该使用一个?
CTE
WITH cte (Column1, Column2, Column3)
AS
(
SELECT Column1, Column2, Column3
FROM SomeTable
)
SELECT * FROM cte
Run Code Online (Sandbox Code Playgroud)
临时表
SELECT Column1, Column2, Column3
INTO #tmpTable
FROM SomeTable
SELECT * FROM #tmpTable
Run Code Online (Sandbox Code Playgroud)
JNK*_*JNK 213
这是相当广泛的,但我会尽可能给你一个一般的答案。
CTE...
VIEW的#临时表...
至于何时使用它们,它们有非常不同的用例。如果您将有一个非常大的结果集,或者需要多次引用它,请将其放入#temp表格中。如果它需要递归,是一次性的,或者只是为了逻辑上的简化,aCTE是首选。
此外,CTE应永远不会被用于性能。使用 CTE 几乎永远不会加快速度,因为同样,它只是一个一次性视图。你可以用它们做一些巧妙的事情,但加速查询并不是其中之一。
jco*_*and 30
编辑:
请参阅下面马丁的评论:
CTE 未具体化为内存中的表。它只是封装查询定义的一种方式。在 OP 的情况下,它将被内联并且与刚刚做的一样
SELECT Column1, Column2, Column3 FROM SomeTable。大多数情况下,它们不会预先实现,这就是为什么不返回行的原因WITH T(X) AS (SELECT NEWID())SELECT * FROM T T1 JOIN T T2 ON T1.X=T2.X,还要检查执行计划。尽管有时可能会破坏获得线轴的计划。有一个连接项要求对此提供提示。– 马丁·史密斯 2012 年 2 月 15 日 17:08
原答案
CTE 创建在内存中使用的表,但仅对它后面的特定查询有效。使用递归时,这可能是一种有效的结构。
您可能还想考虑使用表变量。这是用来作为一个临时表使用,可以多次使用,而无需重新物化为每个加盟。此外,如果您现在需要保留一些记录,请在下一次选择后添加更多记录,在另一个操作后添加更多记录,然后仅返回那些少数记录,那么这可能是一个方便的结构,因为它不会执行后不需要删除。大多数情况下只是语法糖。但是,如果您保持较低的行数,则它永远不会出现在磁盘上。请参阅SQL Server 中的临时表和表变量有什么区别?更多细节。
临时表实际上是在磁盘上创建的表,只是在每个人都知道的特定数据库中可以删除。好的开发人员有责任在不再需要这些表时销毁它们,但 DBA 也可以擦除它们。
临时表有两种:本地表和全局表。就 MS Sql Server 而言,您使用#tableName本地##tableName名称和全局名称(注意使用单个或双 # 作为标识特征)。
请注意,与表变量或 CTE 不同,临时表可以应用索引等,因为这些是正常意义上的合法表。
一般来说,如果我已经有一个小数据集并且想快速编写一些小代码的脚本,我会使用临时表来进行更长或更大的查询,以及 CTE 或表变量。经验和其他人的建议表明,您应该在返回少量行的情况下使用 CTE。如果您有大量数字,您可能会受益于在临时表上建立索引的能力。
小智 19
该接受的答案在这里说:“一个CTE不应该被用于性能” -但是,这可能会误导。在 CTE 与临时表的上下文中,我刚刚从一组存储过程中删除了一大堆垃圾,因为一些傻瓜一定认为使用临时表几乎没有开销。除了在整个过程中合法地重新使用的那些之外,我把很多东西都塞进了 CTE 。通过所有指标,我获得了大约 20% 的性能。然后我着手删除所有试图实现递归处理的游标。这是我看到最大收获的地方。我最终将响应时间缩短了 10 倍。
CTE 和临时表确实有非常不同的用例。我只想强调,虽然不是万能药,但对 CTE 的理解和正确使用可以在代码质量/可维护性和速度方面带来一些真正的显着改进。因为我掌握了它们,所以我认为临时表和游标是 SQL 处理的大忌。我现在几乎可以使用表变量和 CTE 处理几乎所有内容。我的代码更干净、更快。
Con*_*lls 16
CTE 可能会在查询中重复调用,并且每次被引用时都会对其进行评估 - 这个过程可以是递归的。如果它只被引用一次,那么它的行为就像一个子查询,尽管 CTE 可以参数化。
临时表是物理持久化的,并且可以被索引。在实践中,查询优化器也可能在幕后持久化中间连接或子查询结果,例如在假脱机操作中,因此严格来说 CTE 的结果永远不会持久化到磁盘上是不正确的。
IIRC 表变量(另一方面)始终是内存中的结构。
Dav*_*tch 10
使用 CTE 的主要原因是访问窗口函数row_number()和其他各种函数。
这意味着您可以非常快速和高效地执行诸如获取每个组的第一行或最后一行之类的操作 -在大多数实际情况下比其他方式更有效。
with reallyfastcte as (
select *,
row_number() over (partition by groupingcolumn order by sortingcolumn) as rownum
from sometable
)
select *
from reallyfastcte
where rownum = 1;
Run Code Online (Sandbox Code Playgroud)
您可以使用相关子查询或使用子查询运行与上述类似的查询,但 CTE 在几乎所有情况下都会更快。
此外,CTE 确实可以帮助简化您的代码。这可以带来性能提升,因为您更了解查询并且可以引入更多业务逻辑来帮助优化器更具选择性。
此外,如果您了解您的业务逻辑并知道应该首先运行查询的哪些部分,CTE 可以提高性能 - 通常,将最具选择性的查询放在最前面,从而导致结果集可以在下一次连接中使用索引并添加option(force order)查询暗示
最后,CTE 默认不使用 tempdb,因此您可以通过使用它们来减少对该瓶颈的争用。
如果您需要多次查询数据,或者如果您测量查询并发现通过插入到临时表然后添加索引来提高性能,则应使用临时表。
小智 7
这里似乎对 CTE 有点消极。
我对 CTE 的理解是它基本上是一种临时视图。SQL 既是一种声明性语言,又是一种基于集合的语言。CTE 是声明集合的好方法!不能索引 CTE 实际上是一件好事,因为您不需要!它确实是一种使查询更易于读/写的语法糖。任何体面的优化器都会使用基础表上的索引来制定最佳访问计划。这意味着您可以通过遵循基础表上的索引建议来有效地加速 CTE 查询。
此外,仅仅因为您将集合定义为 CTE,并不意味着必须处理集合中的所有行。根据查询,优化器可能会处理“刚好足够”的行以满足查询。也许你的屏幕只需要前 20 个左右。如果您构建了一个临时表,那么您确实需要读取/写入所有这些行!
基于此,我会说 CTE 是 SQL 的一项重要功能,可以在任何使查询更易于阅读的地方使用。我只会考虑一个真正需要处理每条记录的批处理的临时表。即使这样 afaik 也不是真正推荐它,因为在临时表上,数据库很难帮助您进行缓存和索引。最好有一个永久表,其中包含对您的事务唯一的 PK 字段。
我不得不承认,我的经验主要是在 DB2 方面,所以我假设 CTE 在这两种产品中的工作方式相似。如果 CTE 在 SQL 服务器中稍逊一筹,我会很乐意接受纠正。;)
| 归档时间: |
|
| 查看次数: |
191641 次 |
| 最近记录: |