it-swarm.cn

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

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

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

SELECT * FROM TABLE

要么

SELECT column1, colum2, column3, etc. FROM TABLE

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

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

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

鉴于我已经看到的反应,这仍然是一个坏主意,SELECT *永远不应该用于更多技术原因,我曾经有过。

150
Dan Herbert

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

这是我写的关于它的帖子: 选择查询的真正原因是索引覆盖率不好

它的变化也不那么脆弱,因为任何使用数据的代码都将获得相同的数据结构,而不管您将来对表模式所做的更改。

156
Jon Galloway

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

您可能愿意将此视为次要费用,但要意识到您不需要的列必须是:

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

项目#1有许多隐藏成本,包括消除一些潜在的覆盖索引,导致数据页面加载(以及服务器缓存颠簸),导致可能以其他方式避免的行/页面/表锁定。

将此与指定列的可能节省相比,与*相比,唯一可能的节省是:

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

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

对于第2项,差异很小,无法将您推送到不同的数据包大小或网络数据包数量。如果达到SQL语句传输时间是主要问题的程度,则可能需要首先降低语句的速率。

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

对于第4项,当您指定特定列时,如果要处理不同的列集(不是您指定的列),则查询计划缓存可能会变大但 only 。在这种情况下,你 想要 不同的缓存条目,因为你需要不同的计划。

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

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

我的建议是你应该 总是选择特定的列 。请记住,你一遍又一遍地擅长做什么,所以要养成做正确的习惯。

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

57
IDisposable

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

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

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

33
Giorgi

select *有四个重要原因:

  1. 最重要的实际原因是它迫使用户神奇地知道返回列的顺序。最好是明确的,这也可以保护你免受表格的变化,这很好地分为......

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

  3. 列出列名使您的代码更加自我记录,因此可能更具可读性。

  4. 如果您通过网络进行转移(或者即使您不是),您不需要的列也只是浪费。

30
pkh

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

9
ilitirit

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

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

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

我知道数据库专家会为此恨我 - 继续,投票给我 - 但在我的世界里,开发人员时间很少,CPU周期很充足,所以我相应地调整了我保存的东西和我浪费的东西。

6
Herb Caudill

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

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

当然,对于一个小而简单的系统来说,这一切并不重要。

6
VladV

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

4
Yann Ramin

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

明确命名列将有助于您在路上进行维护。在某些时候,您将进行更改或故障排除,并发现自己在询问“使用该列的位置”。

如果您已明确列出名称,则查找对该列的每个引用(通过所有存储过程,视图等)都很简单。只需转储数据库架构的CREATE脚本,然后通过它进行文本搜索。

4
Chris Wuestefeld

你应该真正只选择你需要的字段,只选择所需的字段,即.

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

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

4
Matthew Abbott

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

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

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

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

3
Alexandre Brasil

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

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

不要推测性能, 测量它!

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

3
Paweł Hajdan

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

3
Nick Berardi

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

3
BrewinBombers

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

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

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

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

2
Jorge Córdoba

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

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

2
kennytm

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

2
Don

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

您的客户端软件不应该依赖于返回字段的顺序,所以这也是一个废话。

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

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

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

2
user9385

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

1
Keith

更好的做法之一是明确说明您想要哪些列是因为表结构可能会在未来发生变化。

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

至于什么是更快,我会尊重他人的专业知识。

1
dpollock

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

它不像在SQl服务器中列出列很难或甚至耗时。您只需将它们从对象浏览器中拖出(您可以通过从Word列拖动来一次性完成)。为您的系统带来永久的性能损失(因为这可以减少索引的使用,因为通过网络发送不需要的数据成本很高)并且更有可能在数据库发生变化时出现意外问题(有时列会增加你不希望用户看到例如)只是为了节省不到一分钟的开发时间是短视和不专业的。

1
HLGEM

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

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

SELECT foo,bar FROM小部件;

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

1
Faisal

如果想要获取诸如列数之类的元数据,则SELECT *是必需的。

1
Mark Etable

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

1
Mike

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

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

1
Mark

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

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

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

0
Scott Lawrence

为此会受到抨击,但我做了一个select *,因为几乎所有的数据都是从SQL Server Views中重新获得的,它将多个表中所需的值预先组合成一个易于访问的View。

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

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

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

0
klkitchens

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

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

0
cazlab

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

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

0
DamienG

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

0
Jeff Hubbard

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

  • 如果您需要按编号索引,或者如果您的驱动程序在blob值上表现得很有趣,并且您需要明确的订单,则您知道订单
  • 如果您应该添加更多字段,则只能阅读所需的字段
  • 如果拼错或重命名字段,而不是记录集/行中的空值,则会出现sql错误
  • 你可以更好地阅读正在发生的事情。
0
Erik

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

0
HLGEM

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

此外,使用表名限定列名。当查询包含联接时,这很关键。如果没有表格资格,可能很难记住哪个列来自哪个表,并且向其他表中添加类似命名的列可能会破坏您的查询。

0
mxsscott

表现明智我看到两者都是平等的评论。但可用性方面有一些+和 - 的

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

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

但我建议总是在你的查询中使用select col1,col2,...如果表格稍后改变,则改变查询...

0
Lahiru Cooray

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

使用select *时出现的另一个问题是,有些白痴选择在表格的中间添加新字段(总是一个不好的做法),如果你使用select *作为插入的基础,那么突然你的列顺序可能是错误,你可能会尝试将社会安全号码插入酬金(发言人可能会因为选择一个非随机的例子而获得报酬的金额),这可能是数据完整性的一个非常糟糕的事情。即使select不是插入,当数据突然出现在报表或网页上的worng命令中时,对客户来说也很糟糕。

我认为使用select *时没有任何情况比使用列列表更可取。您可能认为维护起来比较容易,但实际上它并不会导致您的应用程序因为不需要的字段被添加到表中而无缘无故地变慢。如果您使用了列列表,那么您还必须面对修复不会破坏的事情的问题,因此保存不添加列的时间用完了。

0
HLGEM

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

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

0
siculars

还要记住改变。今天,Select *只选择你需要的列,但是明天它也可以选择我刚刚添加的varbinary(MAX)列而不告诉你,你现在也在检索所有不是3.18千兆字节的二进制数据在昨天的表中。

0
Michael Stum

让我们考虑哪个更快。如果您只需选择所需的数据,那么速度就会更快。但是,在测试中,您可以提取所有数据,以根据业务需求判断可以过滤哪些数据。

0
mikedopp

在某些情况下,SELECT *有利于维护,但一般情况下应避免使用。

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

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

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

0
Cade Roux

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

0
bkaid

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

0
stu

如果您关心速度,请确保使用准备好的语句。否则我与ilitirit一起改变是你保护自己的。

/艾伦

0
Allan Wind

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

0
Sam Cogan

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

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

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

返回的总行数为13,949。

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

0

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

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

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

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

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

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

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

0
Notitze