194

我听说SELECT *在编写 SQL 命令时使用这种做法通常是不好的做法,因为它对SELECT您特别需要的列更有效。

如果我需要SELECT表格中的每一列,我应该使用

SELECT * FROM TABLE

或者

SELECT column1, colum2, column3, etc. FROM TABLE

在这种情况下,效率真的很重要吗?如果您真的需要所有数据,我认为SELECT *在内部会更优化,但我是在对数据库没有真正了解的情况下这么说的。

我很想知道在这种情况下最佳做法是什么。

更新:我可能应该指定我真正想做的唯一情况SELECT *是当我从一个表中选择数据时,我知道所有列都需要被检索,即使添加了新列也是如此。

然而,鉴于我所看到的响应,这似乎仍然是一个坏主意,并且SELECT *永远不应该用于我曾经想过的更多技术原因。

4

48 回答 48

187

选择特定列更好的一个原因是它提高了 SQL Server 可以从索引访问数据而不是查询表数据的可能性。

这是我写的一篇文章: 选择查询是不良索引覆盖率的真正原因

它也不易更改,因为任何使用数据的代码都将获得相同的数据结构,无论您将来对表模式进行何种更改。

于 2008-09-15T18:41:23.110 回答
62

鉴于您选择所有列规范,此时几乎没有区别 。然而,要意识到数据库模式确实发生了变化。如果您使用SELECT *,您将获得添加到表中的任何新列,即使您的代码很可能不准备使用或呈现该新数据。这意味着您将系统暴露在意外的性能和功能更改中。

您可能愿意将此视为一笔不小的成本,但要意识到您仍然不需要的列必须是:

  1. 从数据库中读取
  2. 通过网络发送
  3. 编组到您的流程中
  4. (对于 ADO 类型的技术)保存在内存中的数据表中
  5. 忽略和丢弃/垃圾收集

第 1 项有许多隐藏的成本,包括消除一些潜在的覆盖索引、导致数据页面加载(和服务器缓存抖动)、产生本来可以避免的行/页面/表锁定。

将此与指定列与指定列的潜在节省进行平衡*,唯一可能的节省是:

  1. 程序员不需要重新访问 SQL 来添加列
  2. SQL 的网络传输更小/更快
  3. SQL Server 查询解析/验证时间
  4. SQL Server 查询计划缓存

对于第 1 项,现实情况是您将添加/更改代码以使用您可能添加的任何新列,因此这是一个清洗。

对于第 2 项,差异很少足以将您推入不同的数据包大小或网络数据包数量。如果您到了 SQL 语句传输时间是主要问题的地步,您可能需要首先降低语句速率。

对于第 3 项,没有任何节省,因为*无论如何都必须进行扩展,这意味着无论如何都要咨询表模式。实际上,列出列将产生相同的成本,因为它们必须针对架构进行验证。换句话说,这是一次彻底的清洗。

对于第 4 项,当您指定特定列时,您的查询计划缓存可能会变大,但前提您要处理不同的列集(这不是您指定的)。在这种情况下,您确实需要不同的缓存条目,因为您需要根据需要使用不同的计划。

因此,由于您指定问题的方式,这一切都归结为面对最终模式修改时的问题弹性。如果您将此模式刻录到 ROM 中(它发生了),那么 an*是完全可以接受的。

但是,我的一般准则是您应该只选择您需要的列,这意味着有时看起来您要求所有列,但 DBA 和模式演变意味着可能会出现一些新列,这可能会极大地影响查询.

我的建议是您应该始终选择特定的列。请记住,您一遍又一遍地擅长做的事情,所以要养成正确做事的习惯。

如果您想知道为什么架构可能会在不更改代码的情况下更改,请考虑审计日志、生效/到期日期以及 DBA 为系统性地解决合规性问题而添加的其他类似内容。另一个不正当更改的来源是系统或用户定义字段中其他地方的性能的非规范化。

于 2008-09-15T21:53:18.330 回答
41

您应该只选择您需要的列。即使您需要所有列,最好列出列名,这样 sql server 就不必查询系统表的列。

此外,如果有人向表中添加列,您的应用程序可能会中断。你的程序也会得到它没有预料到的列,它可能不知道如何处理它们。

除此之外,如果表有一个二进制列,那么查询会慢得多并且使用更多的网络资源。

于 2010-06-04T06:48:04.600 回答
36

有四大原因select *是一件坏事:

  1. 最重要的实际原因是它迫使用户神奇地知道返回列的顺序。最好是明确的,这也可以保护您免受表格更改的影响,这很好地融入...

  2. 如果您正在使用的列名称发生更改,最好尽早(在 SQL 调用时)捕获它,而不是在您尝试使用不再存在(或名称已更改等)的列时捕获它。 )

  3. 列出列名使您的代码更加自文档化,因此可能更具可读性。

  4. 如果您通过网络传输(或者即使您不是),您不需要的列只是浪费。

于 2010-06-04T07:03:28.663 回答
10

指定列列表通常是最佳选择,因为如果有人向表中添加/插入列,您的应用程序不会受到影响。

于 2008-09-15T18:50:04.713 回答
9

指定列名肯定更快 - 对于服务器。但如果

  1. 性能不是一个大问题(例如,这是一个网站内容数据库,每个表中有数百行,可能是数千行,但不是数百万行);和
  2. 你的工作是使用一个通用框架创建许多类似的小型应用程序(例如面向公众的内容管理网站),而不是创建一个复杂的一次性应用程序;和
  3. 灵活性很重要(为每个站点定制大量的数据库模式);

那么你最好坚持使用 SELECT *。在我们的框架中,大量使用 SELECT * 允许我们将一个新的网站管理内容字段引入到一个表中,使其具有 CMS 的所有好处(版本控制、工作流/批准等),同时只触及代码几个点,而不是几十个点。

我知道 DB 专家会因此而恨我 - 继续,投票给我 - 但在我的世界里,开发人员的时间很稀缺,CPU 周期很丰富,所以我会相应地调整我节省的和浪费的。

于 2008-09-22T14:11:55.983 回答
6

即使查询不是通过网络发送的,SELECT * 也是一种不好的做法。

  1. 选择比您需要的更多的数据会使查询效率降低 - 服务器必须读取和传输额外的数据,因此需要时间并在系统上产生不必要的负载(不仅是网络,如其他人所提到的,还有磁盘、CPU 等。 )。此外,服务器无法尽可能优化查询(例如,为查询使用覆盖索引)。
  2. 一段时间后,您的表结构可能会发生变化,因此 SELECT * 将返回一组不同的列。因此,您的应用程序可能会获得一个具有意外结构的数据集并在下游某处中断。明确说明列可确保您获得已知结构的数据集,或在数据库级别获得明确的错误(如“未找到列”)。

当然,对于一个小而简单的系统来说,这一切都无关紧要。

于 2010-06-04T07:00:34.790 回答
4

性能方面,带有特定列的 SELECT 可以更快(无需读取所有数据)。如果您的查询确实使用了所有列,则仍然首选带有显式参数的 SELECT。任何速度差异基本上是不明显的并且接近恒定时间。有一天,您的架构会发生变化,这是防止由此引起的问题的良好保险。

于 2008-09-15T18:42:23.403 回答
4

到目前为止,这里已经回答了很多很好的理由,这里还有一个没有提到的理由。

明确命名列将帮助您进行后续维护。在某些时候,您将进行更改或故障排除,并发现自己在问“该列到底在哪里使用”。

如果您已经明确列出了名称,那么通过所有存储过程、视图等查找对该列的每个引用都很简单。只需为您的数据库模式转储一个 CREATE 脚本,然后通过它进行文本搜索。

于 2010-06-04T14:00:57.763 回答
3

肯定定义列,因为 SQL Server 不必对列进行查找来提取它们。如果您定义列,则 SQL 可以跳过该步骤。

于 2008-09-15T18:39:59.633 回答
3

指定您需要的列总是更好,如果您考虑一次,SQL 不必每次查询时都认为“wtf is *”。最重要的是,稍后有人可能会向表中添加您在查询中实际上不需要的列,在这种情况下,通过指定所有列会更好。

于 2008-09-15T18:40:57.293 回答
3

“select *”的问题在于可能会带来您并不真正需要的数据。在实际的数据库查询期间,选定的列并没有真正添加到计算中。真正“繁重”的是数据传输回您的客户端,而您并不真正需要的任何列都只会浪费网络带宽并增加您等待查询返回的时间。

即使您确实使用了从“选择 *...”中获取的所有列,也只是现在。如果将来您更改表格/视图布局并添加更多列,即使您不需要它们,您也会开始将它们带入您的选择中。

“select *”语句不好的另一点是视图创建。如果您使用“select *”创建视图并稍后将列添加到表中,则视图定义和返回的数据将不匹配,您需要重新编译视图才能使其再次工作。

我知道写一个“select *”很诱人,因为我真的不喜欢手动指定查询中的所有字段,但是当你的系统开始发展时,你会发现花这些额外的时间是值得的/努力指定字段,而不是花费更多的时间和精力来消除视图上的错误或优化应用程序。

于 2008-09-15T18:47:35.530 回答
3

虽然明确列出列对性能有好处,但不要发疯。

因此,如果您使用所有数据,请尝试 SELECT * 为简单起见(想象有很多列并执行 JOIN... 查询可能会变得很糟糕)。然后 - 测量。与明确列出列名的查询进行比较。

不要猜测性能,测量它!

当您有一些包含大数据的列(如帖子或文章的正文)并且在给定的查询中不需要它时,显式列表最有帮助。然后通过不在您的答案数据库服务器中返回它可以节省时间、带宽和磁盘吞吐量。您的查询结果也会更小,这对任何查询缓存都有好处。

于 2008-09-15T18:47:53.843 回答
3

您真的应该只选择您需要的字段,并且只选择所需的数字,即

SELECT Field1, Field2 FROM SomeTable WHERE --(constraints)

在数据库之外,动态查询存在注入攻击和畸形数据的风险。通常,您可以使用存储过程或参数化查询来解决这个问题。此外(虽然问题不大)每次执行动态查询时服务器都必须生成执行计划。

于 2010-06-04T06:50:01.973 回答
2

如果您使用 * 或列,则选择同样有效(就速度而言)。

区别在于内存,而不是速度。当您选择多个列时,SQL Server 必须分配内存空间来为您提供查询服务,包括您请求的所有列的所有数据,即使您只使用其中之一。

就性能而言,重要的是执行计划,而这又在很大程度上取决于您的 WHERE 子句以及 JOIN、OUTER JOIN 等的数量......

对于您的问题,只需使用 SELECT *。如果您需要所有列,则没有性能差异。

于 2008-09-15T18:43:12.700 回答
2

与 * 相比,使用显式字段名称并不快,当且仅当您需要获取所有字段的数据时。

您的客户端软件不应该依赖于返回字段的顺序,所以这也是无稽之谈。

您可能(尽管不太可能)需要使用 * 获取所有字段,因为您还不知道存在哪些字段(想想非常动态的数据库结构)。

使用显式字段名称的另一个缺点是,如果它们很多并且它们很长,那么它会使阅读代码和/或查询日志更加困难。

所以规则应该是:如果你需要所有字段,使用*,如果你只需要一个子集,明确命名它们。

于 2008-09-15T19:02:31.687 回答
2

结果太大了。从 SQL 引擎生成结果并将结果发送到客户端的速度很慢。

客户端作为一个通用的编程环境,不是也不应该被设计为过滤和处理结果(例如 WHERE 子句、ORDER 子句),因为行数可能很大(例如数千万行)。

于 2010-06-04T06:47:48.920 回答
2

只要您的列仍然存在(以任何顺序),命名您希望在应用程序中获得的每一列还可以确保您的应用程序在有人更改表时不会中断。

于 2010-06-04T06:58:37.567 回答
2

性能方面,我看到两者都是平等的。但可用性方面有一些+和-

当您在查询中使用 (select *) 并且有人更改表并添加上一个查询不需要的新字段时,这是不必要的开销。如果新添加的字段是 blob 或图像字段怎么办???你的查询响应时间会很慢。

另一方面,如果您使用 (select col1,col2,..) 并且表被更改并添加了新字段,并且如果结果集中需要这些字段,则您始终需要在表更改后编辑您的选择查询。

但我建议始终在您的查询中使用 select col1,col2,... 并在以后更改表时更改查询...

于 2015-03-12T09:48:05.057 回答
1

这取决于您的数据库服务器的版本,但现代版本的 SQL 可以以任何一种方式缓存计划。我会说使用您的数据访问代码最易于维护的任何东西。

于 2008-09-15T18:43:37.270 回答
1

最好的做法是准确说明您想要的列的一个原因是因为表结构将来可能会发生变化。

如果您正在使用基于索引的方法手动读取数据以使用查询结果填充数据结构,那么将来当您添加/删除列时,您将很难找出问题所在。

至于什么更快,我会听从其他人的专业知识。

于 2008-09-15T18:44:17.223 回答
1

与大多数问题一样,这取决于您想要实现的目标。如果您想创建一个允许任何表中的所有列的数据库网格,那么“选择 *”就是答案。但是,如果您只需要某些列并且很少从查询中添加或删除列,那么请单独指定它们。

它还取决于您要从服务器传输的数据量。如果其中一列被定义为备忘录、图形、blob 等,而您不需要该列,则最好不要使用“Select *”,否则您将获得一大堆您不需要的数据想要,你的表现可能会受到影响。

于 2008-09-15T19:07:53.967 回答
1

补充一下其他人所说的,如果您选择的所有列都包含在索引中,则将从索引中提取您的结果集,而不是从 SQL 中查找其他数据。

于 2008-09-15T21:43:44.793 回答
1

如果要获取列数等元数据,SELECT * 是必需的。

于 2008-11-09T13:33:49.783 回答
1

我会为此受到猛烈抨击,但我选择 * 因为几乎我所有的数据都是从 SQL Server 视图中检索的,这些视图将多个表中所需的值预先组合到一个易于访问的视图中。

然后,我确实希望视图中的所有列在将新字段添加到基础表时都不会改变。这还有一个额外的好处,就是允许我更改数据的来源。视图中的 FieldA 可能会被计算一次,然后我可以将其更改为静态的。无论哪种方式,View 都为我提供了 FieldA。

这样做的好处是它允许我的数据层获取数据集。然后它将它们传递给我的 BL,然后它可以从它们创建对象。我的主应用程序只知道对象并与之交互。我什至允许我的对象在传递数据行时自行创建。

当然,我是唯一的开发人员,所以这也有帮助:)

于 2009-11-05T16:46:59.190 回答
1

上面每个人都说的,加上:

如果您正在努力获得可读可维护的代码,请执行以下操作:

SELECT foo, bar FROM 小部件;

立即可读并显示意图。如果你打那个电话,你就知道你会得到什么。如果小部件只有 foo 和 bar 列,那么选择 * 意味着您仍然需要考虑返回的内容,确认订单映射正确等。但是,如果小部件有更多列但您只对 foo 感兴趣和 bar,那么当您查询通配符然后只使用返回的部分内容时,您的代码就会变得混乱。

于 2010-06-04T07:54:14.453 回答
1

请记住,如果根据定义您有一个内部连接,则您不需要所有列,因为连接列中的数据是重复的。

在 SQl 服务器中列出列并不困难甚至耗时。您只需从对象浏览器中拖动它们(您可以通过从单词列中拖动来一次性完成)。对您的系统造成永久性的性能影响(因为这可以减少索引的使用,并且因为通过网络发送不需要的数据代价高昂),并且在数据库更改时更有可能出现意外问题(有时会添加列例如,您不希望用户看到)只是为了节省不到一分钟的开发时间是短视和不专业的。

于 2010-06-04T13:21:01.870 回答
1

这是一个旧帖子,但仍然有效。作为参考,我有一个非常复杂的查询,包括:

  • 12张桌子
  • 6 左连接
  • 9个内连接
  • 所有 12 个表共有 108 列
  • 我只需要 54 列
  • 一个 4 列的 Order By 子句

当我使用 Select * 执行查询时,平均需要 2869 毫秒。当我使用 Select 执行查询时,平均需要 1513 毫秒。

返回的总行数为 13,949。

毫无疑问,选择列名意味着比 Select * 更快的性能

于 2019-05-04T14:29:06.023 回答
0

绝对定义每次要选择的列。没有理由不这样做,性能改进非常值得。

他们永远不应该选择“SELECT *”

于 2008-09-15T18:43:53.230 回答
0

如果您需要每一列,那么只需使用 SELECT * 但请记住,顺序可能会发生变化,因此当您使用结果时,按名称而不是按索引访问它们。

我会忽略有关 * 需要如何获取列表的评论 - 解析和验证命名列的机会等于处理时间,如果不是更多的话。不要过早地优化 ;-)

于 2008-09-15T18:44:14.103 回答
0

在执行效率方面,我不知道有任何显着差异。但是为了程序员的效率,我会写字段的名称,因为

  • 如果您需要按数字索引,或者您的驱动程序在 blob 值上的行为很有趣,您就知道顺序,并且您需要一个明确的顺序
  • 如果您应该添加更多字段,您只阅读您需要的字段
  • 如果您拼写错误或重命名字段,而不是记录集/行中的空值,则会收到 sql 错误
  • 您可以更好地阅读正在发生的事情。
于 2008-09-15T18:44:47.517 回答
0

嘿,实用一点。在原型设计时使用 select *,在实施和部署时选择特定列。从执行计划的角度来看,两者在现代系统上是相对相同的。但是,选择特定列会限制必须从磁盘检索、存储在内存中和通过网络发送的数据量。

最终最好的计划是选择特定的列。

于 2008-09-15T18:49:37.210 回答
0

还要记住变化。今天,Select * 只选择您需要的列,但明天它也可能选择我刚刚添加的 varbinary(MAX) 列,而您现在还检索了所有 3.18 GB 的二进制数据昨天在桌子上。

于 2008-09-15T18:51:44.443 回答
0

让我们想想哪个更快。如果您可以只选择您需要的数据,那么它会更快。但是在测试中可以拉取所有数据,根据业务需求判断哪些数据可以过滤掉。

于 2008-09-15T18:55:14.170 回答
0

好吧,这实际上取决于您的指标和目的:

  1. 如果您有 250 列并且想要(确实)全部选择它们,如果您想在同一天回家,请使用 select * :)
  2. 如果您的编码需要灵活性并且需要的表很小,那么再次选择 * 可以帮助您更快地编码并更轻松地维护它。
  3. 如果您想要强大的工程和性能:
    • 如果它们只是几个,请写下您的列名,或者
    • 编写一个工具,让您轻松选择/生成列名

根据经验,当我需要选择所有列时,我会使用“select *”,除非我有非常具体的理由不这样做(另外,我认为在有很多很多列的表上更快)

最后但并非最不重要的一点是,您希望如何添加或删除表中的列以影响您的代码或其维护?

于 2008-09-15T19:07:09.617 回答
0

两者的主要区别在于来回传递的数据量。任何关于时间差的论点都存在根本缺陷,因为“select *”和“select col1, ..., colN”会导致数据库引擎执行相同数量的相对工作。但是,每行传输 15 列与每行 5 列是 10 列的差异。

于 2008-09-15T19:12:32.130 回答
0

如果您关心速度,请确保使用准备好的语句。否则,我认为改变是你保护自己免受的影响。

/艾伦

于 2008-09-15T19:51:04.143 回答
0

我总是建议指定您需要的列,以防万一您的架构发生更改并且您不需要额外的列。

此外,用表名限定列名。当查询包含连接时,这一点至关重要。如果没有表限定条件,可能很难记住哪一列来自哪个表,并且将类似名称的列添加到其他表之一可能会破坏您的查询。

于 2008-09-15T20:01:19.703 回答
0

使用特定的字段名称,因此如果有人更改了您的表格,您不会得到意外的结果。关于主题:在进行插入时始终指定字段名称,因此如果您稍后需要添加列,则不必在生产版本中同时返回并修复程序并更改数据库。

于 2008-09-15T20:11:56.420 回答
0

我发现如果其他开发人员可能使用代码,或者数据库可能会更改,那么列出列名尤其重要,以便您始终获得一致的数据。

于 2008-09-15T20:42:13.630 回答
0

效率是否重要在很大程度上取决于生产数据集的大小(及其增长率)。如果您的数据集不会那么大,并且它们不会那么快增长,那么选择单个列可能不会带来太多性能优势。

随着更大的数据集和更快的数据增长速度,性能优势变得越来越重要。

要以图形方式查看是否有任何区别,我建议使用查询分析器查看 SELECT * 和等效的 SELECT col1、col2 等的查询执行计划。这应该告诉您这两个查询中哪一个更有效。您还可以生成一些不同数量的测试数据,看看时间是什么。

于 2008-09-15T20:51:05.933 回答
0

当您有一个连接时,不使用 select * 对性能尤其重要,因为根据定义,至少两个字段包含相同的数据。您不想浪费网络资源将不需要的数据从数据库服务器发送到应用程序或 Web 服务器。使用 select * 似乎更容易,但这是一种不好的做法。由于将列名拖到查询中很容易,因此只需这样做即可。

使用 select * 时出现的另一个问题是有些白痴选择在表的中间添加新字段(总是一个不好的做法),如果您使用 select * 作为插入的基础,那么突然您的列顺序可能是错了,您可能会尝试将社会安全号码插入酬金(演讲者可能会获得报酬以选择非随机示例的金额),这可能对数据完整性非常不利。即使选择不是插入,当数据在报表或网页上突然处于磨损顺序时,它对客户来说也很糟糕。

我认为使用 select * 比使用列列表更可取。您可能认为它更易于维护,但实际上并非如此,并且当您不需要的字段被添加到表中时,它会导致您的应用程序无缘无故变慢。如果您使用列列表,您还必须面对修复不会损坏的问题的问题,因此您节省的不添加列的时间已经用完了。

于 2008-09-16T13:38:22.113 回答
0

在某些情况下 SELECT * 有利于维护目的,但通常应避免使用。

这些是特殊情况,例如视图或存储过程,您希望在其中传播基础表中的更改,而无需更改使用该表的每个视图和存储过程。即使那样,这本身也可能导致问题,例如在您有两个视图连接的情况下。一个基础表发生更改,现在视图不明确,因为两个表都有一个同名的列。(请注意,只要您没有使用表前缀限定所有列,就会发生这种情况)。即使有前缀,如果你有这样的结构:

SELECT A. , B. - 您可能会遇到客户现在难以选择正确字段的问题。

一般来说,我不使用 SELECT *,除非我做出有意识的设计决策并指望相关风险很低。

于 2008-09-18T21:58:41.380 回答
0

对于直接查询数据库(例如在 sqlplus 提示符下或通过数据库管理工具),选择 * 通常很好——它省去了写出所有列的麻烦。

另一方面,在应用程序代码中最好枚举列。这有几个好处:

  • 代码更清晰
  • 您将知道返回结果的顺序(这可能对您很重要,也可能不重要)
于 2008-09-18T22:08:31.900 回答
0

我看到有几个人似乎认为指定列需要更长的时间。由于您可以从对象浏览器中拖动列列表,因此在查询中指定列(如果您有很多列并且需要花费一些时间将它们放在单独的行上)可能需要额外的时间。为什么人们认为这很耗时?

于 2008-12-03T22:25:22.067 回答
0

如果您确实需要所有列,这SELECT * 可能没问题 - 但您仍然应该单独列出它们。您当然不应该从表中选择所有行 - 即使应用程序和数据库位于同一服务器或网络上。传输所有行需要时间,尤其是随着行数的增长。您应该至少有一个 where 子句过滤结果,和/或对结果进行分页以仅选择需要显示的行子集。根据您使用的应用程序语言,存在几种 ORM 工具,以帮助查询和分页您需要的数据子集。例如,在 .NET Linq to SQL、Entity Framework 和 nHibernate 中,所有这些都将为您提供帮助。

于 2010-06-04T06:53:57.250 回答
-3

如果记录遍历 Internet,则可以通过限制返回的列来获得巨大的性能提升。

于 2008-09-15T18:58:51.213 回答
-3

When we need all columns, I think select * is faster than all columns.

于 2020-09-29T13:05:15.543 回答