172

从这篇文章如何在以下过程中使用 ROW_NUMBER?

有两个版本的答案,一个使用 asub-query另一个使用 aCTE来解决相同的问题。

那么,使用 aCTE (Common Table Expression)而不是“子查询”有什么好处(因此,查询实际在做什么更具可读性)

使用CTEover的唯一好处sub-select是我实际上可以sub-query. 当 CTE 用作简单(非递归)CTE 时,这两者之间还有其他区别吗?

4

10 回答 10

122

在子查询与简单(非递归)CTE 版本中,它们可能非常相似。您必须使用分析器和实际执行计划来发现任何差异,这将特定于您的设置(因此我们无法完整地告诉您答案)。

一般来说; _ CTE 可以递归使用;子查询不能。这使得它们特别适合树结构。

于 2009-04-01T19:21:09.560 回答
100

公共表表达式的主要优点(当不将其用于递归查询时)是封装,而不是必须在您希望使用它的每个地方声明子查询,您可以定义一次,但有多个引用给它。

但是,这并不意味着它只执行一次(根据这个答案的先前迭代,感谢所有评论过的人)。如果多次引用,查询肯定有可能被多次执行;查询优化器最终决定如何解释 CTE。

于 2009-04-01T19:22:27.217 回答
17

CTE's 对递归最有用:

WITH hier(cnt) AS (
        SELECT  1
        UNION ALL
        SELECT  cnt + 1
        FROM    hier
        WHERE   cnt < @n
        )
SELECT  cnt
FROM    hier

将返回@n行(最多101)。对日历、虚拟行集等很有用。

它们也更具可读性(在我看来)。

除此之外,CTE's 和subqueries是相同的。

于 2009-04-01T19:26:26.147 回答
11

一个未提及的区别是单个 CTE 可以在联合的多个部分中引用

于 2012-02-19T01:59:42.580 回答
8

除非我遗漏了什么,否则您可以很容易地命名 CTE 和子查询。

我想主要的区别是可读性(我发现 CTE 更具可读性,因为它在前面而不是在中间定义了您的子查询)。

如果你需要用递归做任何事情,那么用子查询来做这件事会有点麻烦;)

于 2009-04-01T19:22:10.087 回答
8

没有人提到的一个重要事实是(至少在 postgres 中),CTE 是优化围栏:

https://blog.2ndquadrant.com/postgresql-ctes-are-optimization-fences/

也就是说,它们将被视为自己的原子查询,而不是折叠到整个查询计划中。我缺乏提供更好解释的专业知识,但您应该检查您正在使用的 sql 版本的语义;对于高级用户,如果您是控制查询计划器的专家级别,则能够创建优化围栏可以提高性能;然而,在 99% 的情况下,您应该避免试图告诉查询规划器该做什么,因为您认为会更快的可能比它认为会更快的更糟。:-)

于 2017-08-03T23:55:28.270 回答
6

添加到其他人的答案中,如果您多次使用同一个子查询,则可以用一个 CTE 替换所有这些子查询。这使您可以更好地重用您的代码。

于 2009-09-23T21:48:35.733 回答
4

您还需要了解的一件事是,在旧版本的 SQL Server 中(是的,许多人仍然需要支持 SQL Server 2000 数据库),不允许 CTE,然后派生表是您的最佳解决方案。

于 2011-01-26T16:18:20.507 回答
2

提示:(最大递归 n)

您可以通过在子句中使用MAXRECURSION提示和032,767之间的值来限制特定语句允许的递归级别数OPTION

例如,您可以尝试:

OPTION 
      (MAXRECURSION 150)

GO
于 2015-03-31T11:47:51.220 回答
1
  1. 使用 CTE,您可以使用递归。

  2. 使用 CTE,您只需编写一次,但您可以在查询中的多个位置引用它。因此,它可以让您避免重复自己,并且还可以使查询更易于阅读和解释(即使在查询只引用一次的情况下)。

  3. CTE 似乎向查询优化器提供有关其自身的元数据,因此如果在同一查询中多次引用 CTE(例如,如果它连接到自身),则查询优化器可能会使用该元数据来改进整体查询执行计划(这似乎不会发生在子查询中)。

因此,总而言之,如果您想使用递归,或者您认为它会使您的代码更美观且更易于解释,或者您多次使用相同的子查询,请使用 CTE。

于 2021-08-16T11:27:39.987 回答