使用“Select *”和“Select [列名清单]”有什么区别?

27

我正在使用MS SQL Server 2005。对于SQL引擎来说,以下两种日期格式是否有区别:

SELECT * FROM MyTable;

SELECT ColA, ColB, ColC FROM MyTable;

如果 ColA、ColB 和 ColC 分别代表表中的每一列,那么它们相同的话,是否有理由仍然使用第二个?我有一个重度依赖于 LINQ 的项目,不确定它生成的标准 SELECT * 是否是一种不好的实践,或者我应该总是在 .Select() 中指定我想要的列。

编辑:为了清晰起见,将“当 ColA、ColB 和 ColC 都是表中的列时?”更改为“当 ColA、ColB 和 ColC 代表表中的每一列时?”


1
参见:https://dev59.com/YnVD5IYBdhLWcg3wKYT- - Annika Backstrom
18个回答

40

通常情况下,最好明确地指定需要查询的列,所以Select col1, col2 from Table更好。原因是在某个时刻可能会向该表添加额外的列,这将导致从查询中带回不必要的数据。

但这并不是一条硬性规则。


2
在许多情况下,这也会导致依赖代码出现故障。特别是在那些不使用INSERT语句上的列列表的懒惰开发人员所处的环境中,这一点尤为明显。 - Pittsburgh DBA
3
有些情况下,明确指出意思可能需要更改使用该表的每个代码,因为您确实希望新列几乎出现在所有地方。虽然通常仍需要更改视图代码,但在这些情况下,只需选择*仍可以将工作量减少一半。这完全取决于您正在做什么以及您未来的计划是什么。 - Lie Ryan
从开发者的角度来看,这并不是很好,因为如果您必须更改或删除列名,它会引起恐慌,因为您必须在所有地方进行更改。但是,@swilliams先生,它是否具有任何性能优势? - santoshe61

17

1) 第二个更明确返回哪些列。第二个的价值在于你更加明确知道哪些列被返回。

2) 当有比显式使用的列更多的列时,这将涉及返回更少的数据。

3) 如果通过添加新列更改表,则第一个查询会发生变化,而第二个不会。如果您的代码类似于“对于所有返回的列...”,那么如果您使用第一个,则结果会改变,但是第二个则不会。


9

我可能会惹怒很多人,但尤其是当我以后要添加列时,我通常喜欢使用SELECT * FROM table。因为如果我对表进行任何修改,我不想追踪使用该表的所有存储过程,而是只需在应用程序中更改数据访问层类中的内容即可。当然,有些情况下我会指定列,但如果我想从数据库获取完整的“对象”,我宁愿使用“*”。是的,我知道人们会因此而憎恨我,但这使我在向我的应用程序添加字段时更快、更少出现错误。


我不认为你需要过于防御。这是对一个风格上主观的问题的一个有效回答。 :) - Greg D
1
在开发方面,“更快”确实没错。但是,你可能会在几乎每个SELECT语句中浪费I/O。 - Pittsburgh DBA
1
我同意你的观点,我还没有遇到过可以追溯到“select *”与“select column1,column2...”之间性能问题的情况。虽然这种情况可能会发生,但我宁愿在必要时再处理这种异常情况,而不是在99%的情况下进行防御性编码。 - JasonS
我也同意你的观点。在某些情况下,星号显然确实可以使代码更易于维护(特别是如果你有一个不错的IDE和/或良好的编码规范),这往往比性能相关问题更重要。 - Yarik

9
问题的两面是这样的:显式列规范在添加新列时提供更好的性能,但*规范在添加新列时不需要维护。
使用哪种取决于您期望向表中添加什么类型的列以及查询的目的。如果您将表用作对象的后备存储(在LINQ-to-SQL情况下似乎很可能),则可能希望将添加到此表中的任何新列包含在对象中,反之亦然。您正在并行维护它们。因此,对于这种情况,在SELECT子句中使用*规范是正确的。显式规范会在每次更改时给您额外的维护工作,并且如果您没有正确更新字段列表,则会出现错误。
如果查询将返回大量记录,则出于性能原因,最好使用显式规范。
如果两者都是真的,请考虑使用两个不同的查询。

8

您应该指定明确的列清单。使用SELECT *将会带回比您需要的更多的列,从而产生更多的IO和网络流量,但更重要的是,即使存在非聚集覆盖索引(在SQL Server上),这可能也需要额外的查找。


是的!这是明确的最好理由——覆盖索引。 - Michael Haren
被接受的答案似乎满足了更多人对 * 和 col1、col2、col3 之间差异的[误]观念。 - ProfK

5

使用第一种语句(select *)的一些不好的原因包括:

  1. 如果您在以后的时间中增加了一些大字段(如BLOB列),则可能导致应用程序的性能问题。
  2. 如果查询是一个连接两个或多个表的查询,则某些字段可能具有相同的名称。更好的方法是确保您的字段名称不同。
  3. 从编程美学的角度来看,第二个语句会更清楚地表达查询的目的。

我不反对你的回答。但是,大多数数据库在结果集上请求适当的getter时,会使用单独的调用来加载“大对象(BLOB)”类型。因此,只有当您真正想要读取这些列时,性能才会受到影响。 - Raja Anbazhagan

4

当您逐个选择每个字段时,更清楚哪些字段实际上被选择。


3

在大多数情况下,使用SELECT *是一种不好的做法。

  • 如果有人向该表添加一个2GB的BLOB列会怎样?
  • 如果有人向该表添加任何列会怎样?

这是一个等待发生错误的漏洞。


"SELECT *" 不会返回 2 GB 的数据,因此这是无关紧要的。真正重要的是列的添加对相关代码的影响,以及可读性和明确性。 - Pittsburgh DBA
我基本上同意,除了关于 bug 部分。我发现通过获取整行,并且只在一个地方(数据访问层类)处理数据,我已经避免了出现 bug。通常我会在那里处理可能的问题。具有与 SQL 链接的数据模型类是调整东西的好地方。 - stephenbayer
@ P DBA:我说过它会返回2个G吗?我只是在问代码是否能够处理第二个要点所示的表格变化。@SB 你可以编写代码以适应模式的更改,但大多数开发人员不这样做,结果会出现问题。为什么要让自己有机会出错呢? - Mark Brady

3

有几个问题:

  • 很多人在这里发帖反对使用*,并给出了几个好的理由。到目前为止,其他10个回复中只有一个不建议列出列。
  • 当人们在像StackOverflow这样的帮助网站上发布帖子时,通常会对此规则进行例外,因为他们通常不知道您的表中有哪些列或哪些列对您的查询很重要。因此,您会在这里和其他网站上看到很多使用*语法的代码,即使发布者倾向于避免在自己的代码中使用它。

2

往后兼容性会更好。

当您使用时

SELECT * FROM myTable

"myTable"中有3列。您将获得与以下相同的结果:

SELECT Column1, Column2, Column3 FROM myTable

但如果您在将来添加新列,则会得到不同的结果。

当然,如果您更改现有列中的名称,在第一种情况下您将获得结果,在第二种情况下您将收到错误消息(我认为这是应用程序的正确行为)。


1
我不确定在未来发生变化时中断是否是向前兼容的定义。 - Mark Brady
我认为TcKs的观点是,宁可停下来不做也比假装在工作(但实际上不工作)要好。 - Greg D
2
我同意,如果您重命名列并通过列名称访问结果,则应用程序应该中断。如果您仍然通过列名称而不是索引访问结果,则使用*不能更好地保护自己免受重命名的影响。 - Josh
@Greg D 是的,那正是我所指的。 - TcKs

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接