哪个更快/最好?SELECT *或SELECT columnn1, colum2, column3等

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

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

SELECT * FROM TABLE

SELECT column1, colum2, column3, etc. FROM TABLE

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

我很好奇在这种情况下最好的做法是什么。

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

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

94893 次浏览

明确地定义列,因为SQL Server将不需要对列进行查找来拉出它们。如果定义了列,则SQL可以跳过该步骤。

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

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

这是我写的一篇关于它的文章:选择查询的真正原因是索引覆盖不好

它也不太容易更改,因为任何消耗数据的代码都将获得相同的数据结构,而不管您将来对表模式做了什么更改。

在性能方面,具有特定列的SELECT可以更快(不需要读入所有数据)。如果您的查询确实使用了所有列,那么带显式参数的SELECT仍然是首选。任何速度差异基本上都是不明显的,并且接近恒定时间。总有一天你的模式会改变,这是预防由此产生问题的好保险。

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

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

在性能方面真正重要的是执行计划,而执行计划又严重依赖于WHERE子句和JOIN、OUTER JOIN等的数量……

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

这取决于您的DB服务器的版本,但现代版本的SQL可以以任何一种方式缓存该计划。我想说的是,不管你的数据访问代码有什么可维护性,你都要使用它。

每次都定义你想要SELECT的列。没有理由不这样做,性能的提高是非常值得的。

他们不应该给“SELECT *”选项

如果你需要每一列,那么只需使用SELECT *,但记住,顺序可能会改变,所以当你消费的结果访问他们的名字,而不是通过索引。

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

准确地说出需要哪些列是更好的实践的一个原因是,将来可能会对表结构进行更改。

如果您正在使用基于索引的方法手动读入数据,用查询结果填充数据结构,那么将来当您添加/删除列时,您将会头疼地试图找出哪里出了问题。

至于哪种方法更快,我会听取别人的专业意见。

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

  • 如果您需要按数字进行索引,或者您的驱动程序对blob-values的行为很奇怪,那么您需要一个明确的顺序
  • 如果需要添加更多字段,则只读取所需的字段
  • 如果拼写错误或重命名字段,而不是记录集/行中的空值,则会得到sql-error
  • 你可以更好地了解发生了什么。

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

即使您确实使用了来自“select *…”的所有列,这也只是暂时的。如果将来您更改表/视图布局并添加更多列,您将开始在您的选择中引入这些列,即使您不需要它们。

“select *”语句不好的另一个地方是视图创建。如果您使用“select *”创建了一个视图,然后向表中添加列,则视图定义和返回的数据将不匹配,您需要重新编译视图以使它们再次工作。

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

虽然显式列出列对性能有好处,但不要太疯狂。

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

不要猜测性能,测量它!

当你有一些包含大数据的列(比如一篇文章的主体),并且在给定的查询中不需要它时,显式列表是最有用的。然后,通过在应答中不返回它,DB服务器可以节省时间、带宽和磁盘吞吐量。您的查询结果也会更小,这对任何查询缓存都是有利的。

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

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

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

同时也要记住变化。今天,Select *只选择您需要的列,但明天它可能还会选择我刚刚添加的varbinary(MAX)列,而您现在还可以检索所有3.18 gb的二进制数据,这些数据昨天不在表中。

让我们想想哪一个更快。如果你可以选择你需要的数据,那么速度会更快。然而,在测试中,您可以提取所有数据,以判断哪些数据可以根据业务需求过滤掉。

如果记录要遍历internet,那么限制返回的列可以大大提高性能。

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

你的客户端软件不应该依赖于返回字段的顺序,所以这也是毫无意义的。

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

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

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

这取决于你的指标和目的:

  1. 如果你有250列,并且想要全部选中,如果你想当天回家,请使用select *:)
  2. 如果您的编码需要灵活性,并且需要的表很小,那么选择*可以帮助您更快地编码并更容易地维护它。
  3. 如果你想要健壮的工程和性能:
    • 如果只有几个列名,就写出来,或者
    • 编写一个工具,让您轻松地选择/生成列名
    • 李< / ul > < / >

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

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

和大多数问题一样,这取决于你想要达到什么目标。如果你想创建一个db网格,允许任何表中的所有列,那么“Select *”就是答案。但是,如果您只需要某些列,并且很少从查询中添加或删除列,那么可以单独指定它们。

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

两者之间的主要区别是来回传递的数据量。任何关于时间差的争论在“select *”和“select col1,…”, colN”会导致DB引擎执行相同数量的相对工作。但是,每行传输15列与每行传输5列是10列的差异。

如果你关心速度,确保你使用准备好的语句。否则,我是与ilitirit,变化是你保护自己免受。

/艾伦

我总是建议指定您需要的列,以防您的模式发生变化而不需要额外的列。

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

使用特定的字段名,这样如果有人更改了您的表,您就不会得到意想不到的结果。关于主题:在执行插入操作时始终指定字段名,这样如果稍后需要添加列,就不必在生产版本中同时修复程序和更改数据库。

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

效率是否重要很大程度上取决于生产数据集的大小(以及它们的增长率)。如果您的数据集没有那么大,也没有那么快地增长,那么选择单个列可能没有太大的性能优势。

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

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

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

给定你的规范,您选择所有列,此时几乎没有区别。但是,要意识到数据库模式确实会发生变化。如果你使用SELECT *,你将得到任何新列添加到表中,即使在十有八九,你的代码不准备使用或显示这些新数据。这意味着您正在将系统暴露给意外的性能和功能更改。

你可能会认为这是一个很小的开销,但要意识到你不需要的列仍然必须是:

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

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

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

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

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

对于第2项,这种差异很少足以使您使用不同的数据包大小或网络数据包数量。如果SQL语句传输时间是主要问题,那么可能首先需要降低语句的速率。

对于第3项,没有任何节省,因为*的扩展无论如何都必须发生,这意味着无论如何都要咨询表的模式。实际上,列出列也会产生相同的成本,因为它们必须根据模式进行验证。换句话说,这完全是一笔勾销。

对于第4项,当你指定特定的列时,如果你处理不同的列集(这不是你指定的),你的查询计划缓存可以变得更大,但只有。在这种情况下,你想要的不同的缓存项,因为你需要不同的计划。

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

然而,我的一般原则是,你应该只选择你需要的列,这意味着有时看起来就像你在要求所有的列,但是dba和模式进化意味着一些新列可能会出现,这可能会极大地影响查询。

我的建议是你应该总是选择特定的列。记住,你会不断擅长你所做的事情,所以要养成正确做这件事的习惯。

如果您想知道为什么模式可以在不更改代码的情况下更改,可以考虑审计日志、有效/过期日期和dba系统地添加的其他类似内容,以解决遵从性问题。另一个幕后更改的来源是系统中其他地方或用户定义字段的性能反规范化。

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

当使用select *发生的另一个问题是,有白痴选择添加新表中间fo字段(总是坏实践),如果使用select *作为一个插入的基础突然列顺序可能是错的,你可能试图将社会安全号码插入酬金(amoutn钱演讲者可能会选择一个随机的例子),可能对数据完整性是一件非常糟糕的事情。即使选择不是插入,当报告或网页上的数据突然出现错误顺序时,对客户来说也很糟糕。

我认为在任何情况下使用select *都不会比使用列列表更好。您可能认为这样更容易维护,但事实并非如此,而且当您不需要的字段被添加到表中时,会导致您的应用程序毫无理由地变慢。您还必须面对修复问题,如果您使用列列表就不会损坏,因此您节省的不添加列的时间将用于此操作。

在某些情况下,SELECT *适用于维护目的,但一般情况下应该避免使用。

这是一些特殊的情况,比如视图或存储过程,在这些情况下,您希望传播底层表中的更改,而不需要更改使用表的每个视图和存储过程。即使这样,这本身也会引起问题,比如在有两个连接视图的情况下。一个底层表改变了,现在视图是模糊的,因为两个表都有一个具有相同名称的列。(请注意,这种情况可能发生在任何时候,您没有用表前缀限定您的所有列)。即使有前缀,如果你有这样的结构:

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

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

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

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

  • 代码更清晰
  • 你将知道结果返回的顺序(这对你来说可能重要,也可能不重要)

对服务器来说,指定列名肯定更快。但是,如果

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

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

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

如果想要获得元数据,例如列的数量,SELECT *是必需的。

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

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

然后我想要所有的列从视图不会改变,当新字段添加到底层表。这有一个额外的好处,允许我改变数据的来源。视图中的FieldA一次可以被计算,然后我可以将其更改为静态。不管怎样,视图给我提供了FieldA。

它的美妙之处在于它允许我的数据层获得数据集。然后它将它们传递给我的BL,然后可以从它们创建对象。我的主应用程序只知道这些对象并与之交互。我甚至允许我的对象在传递数据箭头时自我创建。

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

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

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

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

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

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

您实际上应该只选择您需要的字段,并且只选择所需的数量,即。

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

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

如果你确实需要所有的列,SELECT * 可能是可以的-但你仍然应该单独列出它们。你当然不应该选择一个表中的所有行——即使应用&数据库在同一服务器或网络上。传输所有行将花费时间,特别是当行数增加时。您至少应该有一个where子句来过滤结果,并且/或者对结果进行分页,以只选择需要显示的行子集。根据您使用的应用程序语言,有几个ORM工具可以帮助查询和分页所需的数据子集。例如,在. net Linq to SQL中,实体框架和nHibernate都可以帮助你做到这一点。

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

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

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

当然,对于一个小而简单的系统来说,所有这些都不太重要。

select *是一个坏东西有四个主要原因:

  1. 最重要的实际原因是,它迫使用户神奇地知道将返回的列的顺序。最好是显式的,这也保护您不受表更改的影响,这将很好地segue到…

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

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

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

上面所有人说的,加上:

如果你正在努力编写可读性强、可维护的代码,可以这样做:

SELECT foo, bar FROM widgets;

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

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

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

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

显式地命名列将帮助您进行后续的维护。在某些情况下,您将进行更改或排除故障,并发现自己在问“这个列到底用在哪里”。

如果显式列出了名称,那么通过所有存储过程、视图等查找对该列的每个引用就很简单了。只需为您的DB模式转储一个CREATE脚本,并在其中进行文本搜索。

就性能而言,我看到的评论说两者是相等的。但是在可用性方面有一些+和-

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

另一方面,如果你使用一个(select col1,col2,..),如果表被修改并添加了新的字段,如果结果集中需要这些字段,你总是需要在表修改后编辑你的选择查询。

但我建议总是使用select col1 col2…在你的查询和修改查询,如果表改变以后…

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

  • 12个表
  • 6左连接
  • 9个内连接
  • 12个表共108列
  • 我只需要54列
  • 一个4列的Order By子句
当我使用Select *执行查询时,平均花费2869ms。 当我使用Select执行查询时,它平均需要1513ms

返回的总行数为13,949。

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

当我们需要所有列时,我认为select *比所有列都快。