4

如果我们有一个VIEW_MYTABLE包含 50 列的 SQL 视图。

选项 1

with CTE_MYQUERY1 as (
  select [VIEW_MYTABLE].*
  from [VIEW_MYTABLE]
  /*some complex where clause*/
)

选项 2

with CTE_MYQUERY2 as (
  select [COLUMN_1], [COLUMN_2], [COLUMN_3], ...., [COLUMN_10]
  from [VIEW_MYTABLE]
  /*some complex where clause*/
)

据我了解,定义列的选择总是比select *语句快。请注意,在第二个查询中,我只选择了视图中 50 列中的 10 列。

我得到的结果都一样吗?谁能让我知道 CTE 在内部是如何工作的,它是否首先生成结果集,然后将其提供给后续查询(SELECT在我的情况下为查询)?

4

3 回答 3

7

我希望这两个查询之间的运行时绝对没有明显的差异。

但是,我仍然反对SELECT *,而不是出于性能原因。有一个由来已久的神话,即 SELECT * 效率较低,因为引擎必须在元数据中查找列名,但事实是仍然存在一个查找来验证您编写的列名,并且无论结果集大小如何,人类都不会注意到检索名称的额外成本。

我反对 SELECT * 的原因是:

  • 您不太可能需要表中的所有列(或所有行,但这是另一回事)。如果您拉回的列比您需要的多,那么您正在执行不必要的 I/O,并且可能会强制 SQL Server 执行表/聚集索引扫描,而它本可以对更精简的索引执行扫描。

  • 即使您确实需要所有列,使用 SELECT * 也可能会在以后的代码中导致难以检测的问题。如果有人在表格中间插入一列怎么办?删除一列?添加一列?重命名列?其中一些会立即被捕获,但我已经展示了这可能导致各种难以调试的问题的案例。


至于 CTE 一般如何工作,这是一个相当广泛的问题。我将从这些文章开始:

http://www.simple-talk.com/sql/t-sql-programming/sql-server-cte-basics/

https://docs.microsoft.com/en-us/previous-versions/sql/sql-server-2008/ms190766(v=sql.100)

于 2012-08-24T20:06:06.593 回答
1

损害性能的主要方法SELECT *是导致查询浪费时间检索比实际需要的更多的数据。但它是SELECT查询主要部分中的子句决定检索哪些数据。* (非递归)公用表表达式可以被认为是一种一次性视图。CTE 中未在使用它的查询中引用的任何列最终将被有效地忽略。类似于查询视图时,引擎不一定会抓取视图中的每一列,而只会抓取您要求的每一列。

我的猜测是,这两种 CTE 的性能相同,因为使用它们的查询(您在示例中省略了)在两种情况下都是相同的。因此,在您的第一个选项中引用的额外列最终不会对完整查询检索到的数据产生任何影响。

*补充:为了清楚起见,这只是SELECTs 的情况。WHEREandJOIN子句将影响无论出现在何处都必须读取哪些列。

于 2012-08-24T20:30:42.227 回答
0

不要向客户端返回比绝对必要更多的列或行数据。这只会增加服务器上的磁盘 I/O 和网络流量,这都会损害性能。在SELECT语句中,不要使用SELECT *返回行,始终在SELECT语句中准确指定此特定查询需要返回哪些列,而不是更多列。在大多数情况下,一定要包含一个WHERE子句,以减少发送到客户端需要立即执行手头任务的那些行的数量或行数。

在我看来,最大的区别在于您的复杂WHERE条款,主要行动发生的地方,涉及的索引等。

综上所述,我相信第二个在几乎所有情况下都会表现得更好。

查看Steve Jones 在 SQL Central 上的这篇详细文章。

于 2012-08-24T19:58:23.530 回答