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

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

SELECT * FROM TABLE




SELECT column1, colum2, column3, etc. FROM TABLE


这种情况下效率真的重要吗?我认为,如果您确实需要所有数据,则SELECT *会在内部更理想,但是我说这并不是真正了解数据库。

我很好奇知道最佳实践在这种情况下。

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

但是,鉴于我所看到的回答,这似乎仍然是一个糟糕的主意,出于我想过的更多技术原因,切勿使用SELECT *

评论

另请参阅:stackoverflow.com/questions/208925/…

请参阅:stackoverflow.com/questions/262450/…stackoverflow.com/questions/65512/…stackoverflow.com/questions/413819/select-exceptstackoverflow.com/questions/208925/…stackoverflow.com/questions/487578/…stackoverflow .com / questions / 1433971 /…

是的,它是大多数复制品。

#1 楼

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

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

它也较不易更改,因为任何消耗数据的代码都将得到相同的数据结构,而不管将来对表模式所做的更改。

评论


为此+1。如果所有引用的列都存在于一个索引(“覆盖索引”)中,那么您就大吃一惊了。

–伊恩·尼尔森(Ian Nelson)
08年9月15日在18:44

那不是他的问题的答案-“如果我需要选择表中的每一列,...” –在这种情况下,* vs col1,.. coln无关紧要(但这对于程序员来说确实有用,因为*较短!)。

–马特·罗吉什(Matt Rogish)
08/09/15在19:23

仍然很重要,因为选择列表是一种合同形式,尤其是如果SQL在存储过程中。

– Eric Z Beard
08/09/15在23:22

尽管乔恩所说的是完全正确的,也是非常正确的观点,但我必须同意,所问的问题是关于它们是否已经要求所有列了。由于这部分问题,真正的问题是面对架构更改时的脆弱性。

–IDisposable
08/09/17在20:01

@MattRogish先生,您正确地知道了这两种方法之间的性能差异(*与all_column_names),尽管我们有成千上万的行,并且使用索引执行SELECT(在WHERE子句中)

– santosh
18-10-31在7:58

#2 楼

根据您选择所有列的说明,目前没有什么区别。但是请意识到,数据库架构确实会发生变化。如果您使用SELECT *,那么即使有可能您的代码也没有准备好使用或展示该新数据,也将向该表中添加任何新列。这意味着您要将系统暴露于意想不到的性能和功能更改。

您可能愿意以较小的费用来解决此问题,但是您意识到不需要的列仍然必须是: br />

从数据库中读取
通过网络发送
编组到您的进程中
(对于ADO类型的技术)保存在内存中的数据表中
被忽略和丢弃的/垃圾回收的

项#1具有许多隐藏的成本,包括消除一些潜在的覆盖索引,导致数据页负载(以及服务器缓存抖动),导致行/页/

将其与指定列而不是*的潜在节省进行平衡,唯一的潜在节省是:

无需重新访问SQL即可添加列
SQL的网络传输更小/更快
SQL Server查询解析/验证时间
SQL Server查询计划缓存
/>
对于项目1,现实是您要添加/更改代码以使用您可能仍会添加的任何新列,因此很容易。

对于项目2 ,这种差异很少会迫使您进入不同的数据包大小或数量的网络数据包。如果到了SQL语句传输时间成为主要问题的地步,则可能需要先降低语句的比率。

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

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

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

但是,我的一般指导原则是,您只应选择所需的列,这意味着有时看起来您正在要求所有这些列,但是DBA和模式演变意味着一些新列可能会严重影响查询。

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

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

评论


“现实是,您将添加/更改代码以使用无论如何都可能会添加的任何新列,因此这很容易。” -仅当您手动按代码中的名称读取每一列时。如果您使用的是自动映射,则不是这种情况,这个问题变得很重要。

–乔什·诺(Josh Noe)
2013年12月2日19:36

#3 楼

您只应选择所需的列。即使您需要所有列,也最好列出列名,以便sql server不必在系统表中查询列。

此外,如果有人向表中添加列,您的应用程序可能会中断。您的程序将获得预期不到的列,并且可能不知道如何处理它们。

此外,如果表具有二进制列,则查询将更慢并且使用更多网络资源。

评论


如此一来,通过使用*,您将为数据库添加额外的工作。好的,这是我没有想到的原因之一。

–安库尔
2010年6月4日下午6:50

+1可能会提早打破/捕获错误。我认为关于效率的讨论是有效的,但YAGNI。

–nailitdown
2010年6月4日在7:36

SQL Server是否仍然不需要验证或检查“ col1”是否在指定的表中,即查询系统表?

–帕特里克(Patrick)
2010年6月4日上午10:10

对性能的最大影响可能与索引有关。如果您要查找的列是用于查找数据的索引的一部分,则服务器将在那里获取数据,如果执行select *,则很有可能必须执行称为书签查找的操作,这需要额外的操作扫描以查找您可能甚至不需要的其余基础数据。

– Cobusve
2010年6月4日在12:12

@Patrick-当场。有很多避免*的充分理由,但这不是其中之一。

–马丁·史密斯
2010-6-4 12:49



#4 楼

select *是一件坏事的主要原因有四个:


最重要的实际原因是它迫使用户神奇地知道将返回列的顺序。最好是显式的,这样也可以保护您免受表更改的影响,这样可以很好地将表锁定为...
如果您正在使用的列名发生更改,则最好及早捕获(在SQL调用时) ),而不是当您尝试使用已不存在的列(或名称已更改等)时。
列出列名可以使您的代码更容易记录在文档中,因此更具可读性。
如果您正在通过网络进行传输(或者即使不是),则不需要的列也很浪费。


评论


“最重要的实际原因是它迫使用户神奇地知道将返回列的顺序。”我不认为这是一个问题。在任何现代DB客户端中,您都按名称而不是顺序读取列。

–乔什·诺(Josh Noe)
2013年12月2日19:39

我倾向于通过C接口运行SQL,所以我真的不知道“数据库客户端”中的最新技术是什么。但是我认为您正在谈论的客户端类型可能正在执行一些非标准的非SQL魔术。 (例如,在SQLite中,查询sqlite3_master以弄清楚如何将*更改为一组名称。)

–pkh
2013年12月2日21:11

接下来,有多少人在使用列名索引的现代应用程序中编写代码?当然,大多数人肯定会使用某种映射器和一整堆缓存来存储允许过时的数据。就个人而言,请先编写代码,然后再担心是否会遇到性能问题。

–科林·怀斯曼
17年7月10日在19:44

#5 楼

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

#6 楼

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



性能不是大问题(例如,这是一个网站内容数据库,每个表中有成百上千行,也许不是几百万行) ; AND
您的工作是使用通用框架创建许多小型的类似应用程序(例如,面向公众的内容管理网站),而不是创建复杂的一次性应用程序; AND

灵活性很重要(为每个站点自定义db模式很多);

那么最好还是坚持使用SELECT *。在我们的框架中,SELECT *的大量使用使我们可以在表中引入新的网站托管内容字段,从而为它提供CMS的所有好处(版本,工作流/批准等),而只需触摸代码即可。几分,而不是几分。

我知道数据库专家会为此而讨厌我-继续,请我投反对票-但在我的世界中,开发人员时间稀少,CPU周期充裕,因此我要相应地调整我所保存的内容还有我的浪费。

评论


它还使ORM更加易于使用。当通过传递查询构建对象来构建查询时,不必一定知道其他哪些代码部分(权限检查,您拥有什么)需要哪些列。因此,为了限制列数,每次查询需要编写时都需要进行调查。 IMO,这毫无意义。当查询确实变慢(日志!)时,可以改善这些查询。

–bytepusher
19年4月12日在7:26

#7 楼

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


选择超出所需数量的数据会使查询效率降低-服务器必须读取和传输额外的数据,因此这会花费时间并给系统(不仅是网络)造成不必要的负载,就像其他人提到的一样,还有磁盘,CPU等)。此外,服务器无法尽最大可能优化查询(例如,对查询使用覆盖索引)。
一段时间后,您的表结构可能会更改,因此SELECT *将返回一组不同的列。因此,您的应用程序可能会获得意外结构的数据集,并在下游某处中断。明确说明各列可确保您获得已知结构的数据集,或在数据库级别获得明确的错误(例如“未找到列”)。一个小型而简单的系统就足够了。

#8 楼

在性能方面,具有特定列的SELECT可以更快(无需读取所有数据)。如果您的查询确实确实使用了ALL列,则仍然建议使用带有显式参数的SELECT。任何速度差异基本上都是不明显的,并且接近恒定时间。有一天,您的架构将发生更改,这是防止出现此问题的良好保证。

评论


您对这种不明显的问题是错误的,因为我对多个数据库所做的检查很明显,即使选择所有列,选择每列也要快得多。在某些情况下,速度要快三倍。

–shahar eldad
19年6月10日在7:13

#9 楼

到目前为止,有很多充分的理由可以回答,这是另一个未提及的理由。

明确命名列将有助于您进行日常维护。在某个时候,您将进行更改或故障排除,并发现自己在问“该列在何处使用”。

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

#10 楼

绝对定义列,因为SQL Server不必对列进行查询即可将其拉出。如果定义列,则SQL可以跳过该步骤。

评论


这是:1)不相关,因为SQL Server必须以两种方式引用表模式(以验证列名或查找已知有效的列名)2)与所询问的问题无关,在该问题中引用了所有列。唯一询问的问题是架构更改后的脆弱性。

–IDisposable
08-09-17在20:03

不推荐使用,因为无论如何都必须验证列。

–约翰·吉布(John Gibb)
10-4-8在17:40

#11 楼

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

评论


这是不正确的:SQL Server仍必须解析每个列,并查看其是否存在于目录中,而它知道“ *”可以(并且,*扩展为所有列)。无论哪种方式,DBMS都可以很容易地做到其中之一(除非您有24,000列),所以我敢打赌,两者都是一样的

–马特·罗吉什(Matt Rogish)
08/09/15在19:25

我认为很多人缺少的更好的一点是,不幸的是,这个答案仅次于是解决的是,如果发生架构/表更改(即添加了新列),它将不会破坏事情。

– Sean Hanley
08年9月15日在19:58

这是完全可以洗的,因为查找*扩展的列与验证提供的列名相同。

–IDisposable
08/09/17在20:07

#12 楼

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

即使您确实使用了“ select * ...”中带入的所有列,也仅此而已。如果将来您更改表/视图的布局并添加更多列,即使您不需要它们,也将开始将其纳入选择范围。

另一个要点是“选择*声明不好是在视图创建上。如果您使用“选择*”创建视图,然后在表中添加列,则视图定义和返回的数据将不匹配,并且您需要重新编译视图以使它们再次起作用。

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

评论


VIEW的观点非常重要。如果向表中添加列,不仅不会获得所有列(尽管*会引起您的思考),而且它们甚至可能与表的实际布局都不匹配。

–Euro Micelli
08/09/15在23:23

#13 楼

虽然显式列出列对性能有好处,但是请不要发疯。

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

不要猜测性能,请对其进行衡量!或文章),并且在给定查询中不需要它。然后,通过不在答案数据库中返回它,DB服务器可以节省时间,带宽和磁盘吞吐量。您的查询结果也将更小,这对任何查询缓存都非常有用。

#14 楼

您实际上应该只选择所需的字段,而仅选择所需的字段,即

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


在数据库之外,动态查询会带来注入攻击和格式错误的风险。数据。通常,您可以使用存储过程或参数化查询来解决此问题。另外(尽管问题不大),但每次执行动态查询时,服务器都必须生成执行计划。

评论


我认为“每次执行动态查询时服务器都必须生成一个执行计划”,我认为这会使查询速度变慢。谢谢。

–安库尔
2010年6月4日在6:52

使用动态sql的性能问题可能只会在非常高的负载情况下才能实现,Sql Server擅长高效地管理查询计划。

–马修·雅培(Matthew Abbott)
2010年6月4日在6:57

#15 楼

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

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

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

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

#16 楼

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

您的客户端软件不应该依赖于返回字段的顺序,所以这也是胡说八道。

(尽管不太可能)您需要获得全部信息使用*的字段,因为您尚不知道存在哪些字段(请考虑非常动态的数据库结构)。

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

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

#17 楼

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

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

评论


因此,如果您需要实际使用所有不同的列,那将是很好的……并且如果您的数据库和应用程序又位于同一台服务器上,那不会有太大的不同吗?

–安库尔
2010年6月4日在6:49

@Ankur:即使在同一台服务器上,也需要通过数据库接口传输数据。

–kennytm
2010年6月4日在6:54

#18 楼

只要您的列仍然存在(以任何顺序),为您希望进入应用程序的每一列命名也可以确保如果有人更改表,您的应用程序不会中断。

#19 楼

它取决于您的数据库服务器的版本,但是现代版本的SQL可以以任何一种方式缓存计划。我想说的是您的数据访问代码中最可维护的内容。

#20 楼

最好确切地指出所需的列的一种较好的做法是,由于表结构将来可能会发生变化。

如果您正在使用基于索引的方法手动读取数据来填充数据结构,查询的结果,然后在将来添加/删除列时,您会头疼着想找出出了什么问题。

关于什么是更快的,我会请其他人提供专业知识。

#21 楼

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

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

#22 楼

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

#23 楼

如果要获取元数据(例如列数),则必须使用SELECT *。

#24 楼

我会为此大吃一惊,但是我选择了*,因为几乎所有数据都是从SQL Server视图中检索的,这些视图将所需的值从多个表中预先组合到一个易于访问的视图中。视图中的所有列(将新字段添加到基础表时都不会更改)。这具有允许我更改数据来源的附加好处。可以一次计算视图中的FieldA,然后将其更改为静态。无论哪种方式,View都可以向我提供FieldA。

其优点是它允许我的数据层获取数据集。然后将它们传递给我的BL,后者可以根据它们创建对象。我的主应用程序仅知道对象并与之交互。我什至允许我的对象在传递数据行时自行创建。

当然,我是唯一的开发人员,因此也有帮助:)

#25 楼

以上每个人所说的内容,以及:

如果您正在努力寻找可读的可维护代码,请执行以下操作: />即刻可读并显示意图。如果您拨打该电话,您就会知道自己正在得到什么。如果窗口小部件仅具有foo和bar列,则选择*意味着您仍然必须考虑要返回的内容,确认顺序已正确映射,等等。但是,如果窗口小部件具有更多列,但您仅对foo感兴趣和bar,那么当您查询通配符而仅使用返回的某些内容时,您的代码就会变得混乱。

#26 楼

并记住,如果按照定义具有内部联接,则不需要所有列,因为联接列中的数据是重复的。

这并不像在SQl服务器中列出列那样困难甚至费时。您只需将它们从对象浏览器中拖过即可(通过从字列中拖拽可以一劳永逸)。要给您的系统带来永久性的性能下降(因为这会减少索引的使用,并且因为通过网络发送不需要的数据的开销很大),并且随着数据库的更改,您更有可能遇到意想不到的问题(有时会添加列您不希望用户看到例如)只是节省不到一分钟的开发时间是短视和不专业的。

#27 楼

在性能方面,我已经看到了两者相同的评论。但在可用性方面,当您在查询中使用(select *)时,如果有一些改变表并添加新字段,则在使用+和-时会出现一些+和-查询这是不必要的开销。如果新添加的字段是Blob或图像字段,该怎么办?那么您的查询响应时间将会非常慢。

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

但是我建议始终在查询中使用select col1,col2,...,如果表以后被更改,请更改查询...

#28 楼

绝对定义每次要选择的列。没有理由不这样做,而且性能提高是值得的。

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

#29 楼

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

我将忽略有关*需求的注释去获取列表-解析和验证命名列的机会等于或等于处理时间。不要过早优化;-)

#30 楼

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


您知道顺序,如果您需要按数字索引,或者您的驱动程序对blob值表现得很幽默,并且您需要确定的顺序
如果需要添加更多的字段,则仅读取所需的字段
如果拼写错误或重命名了字段,则会出现sql错误,而不是记录集/行中的空值
您可以更好地了解正在发生的事情。