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

时间:2008-09-15 18:38:49

标签: sql database

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

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

SELECT * FROM TABLE

SELECT column1, colum2, column3, etc. FROM TABLE

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

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

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

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

48 个答案:

答案 0 :(得分:156)

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

这是我写的关于它的帖子:The real reason select queries are bad index coverage

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

答案 1 :(得分:57)

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

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

  1. 从数据库中读取
  2. 通过网络发送
  3. 编入您的流程
  4. (适用于ADO类型技术)保存在内存中的数据表中
  5. 忽略并丢弃/垃圾收集
  6. 项目#1有许多隐藏成本,包括消除一些潜在的覆盖索引,导致数据页面加载(以及服务器缓存颠簸),导致可能以其他方式避免的行/页/表锁。

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

    1. 程序员不需要重新访问SQL来添加列
    2. SQL的网络传输更小/更快
    3. SQL Server查询解析/验证时间
    4. SQL Server查询计划缓存
    5. 对于第1项,实际情况是您要添加/更改代码以使用您可能添加的任何新列,因此它是一个清洗。

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

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

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

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

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

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

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

答案 2 :(得分:33)

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

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

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

答案 3 :(得分:30)

select *有四个重要原因:

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

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

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

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

答案 4 :(得分:9)

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

答案 5 :(得分:6)

为服务器指定列名称肯定更快。但是如果

  1. 性能不是一个大问题(例如,这是一个网站内容数据库,每个表中有数百甚至数千 - 但不是数百万行); AND
  2. 您的工作是使用通用框架创建许多小型,类似的应用程序(例如面向公众的内容管理网站),而不是创建复杂的一次性应用程序; AND
  3. 灵活性非常重要(为每个站点进行大量自定义数据库架构);
  4. 然后你最好坚持使用SELECT *。在我们的框架中,大量使用SELECT *允许我们将新的网站托管内容字段引入到表中,为其提供CMS的所有好处(版本控制,工作流程/批准等),同时仅触及代码。几点,而不是几十分。

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

答案 6 :(得分:6)

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

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

答案 7 :(得分:4)

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

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

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

答案 8 :(得分:4)

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

答案 9 :(得分:4)

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

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

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

答案 10 :(得分:3)

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

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

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

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

答案 11 :(得分:3)

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

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

不要推测性能,测量它!

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

答案 12 :(得分:3)

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

答案 13 :(得分:3)

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

答案 14 :(得分:2)

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

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

答案 15 :(得分:2)

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

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

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

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

答案 16 :(得分:2)

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

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

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

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

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

答案 17 :(得分:2)

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

答案 18 :(得分:1)

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

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

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

答案 19 :(得分:1)

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

答案 20 :(得分:1)

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

答案 21 :(得分:1)

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

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

答案 22 :(得分:1)

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

答案 23 :(得分:1)

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

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

SELECT foo,bar FROM widgets;

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

答案 24 :(得分:1)

请记住,如果你有一个内连接,你不需要所有的列,因为连接列中的数据会重复。

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

答案 25 :(得分:0)

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

答案 26 :(得分:0)

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

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

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

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

答案 27 :(得分:0)

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

  • 12张桌子
  • 6个左联接
  • 9个内部联接
  • 所有12个表上总共108列
  • 我只需要54列
  • 4列Order By子句

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

返回的总行数为13,949。

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

答案 28 :(得分:0)

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

答案 29 :(得分:0)

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

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

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

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

答案 30 :(得分:0)

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

答案 31 :(得分:0)

有些情况下SELECT *适合维护,但一般情况下应避免使用。

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

这样的结构

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

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

答案 32 :(得分:0)

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

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

答案 33 :(得分:0)

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

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

答案 34 :(得分:0)

就执行效率而言,我并不知道有任何显着差异。但是对于程序员的效率,我会写出字段的名称,因为

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

答案 35 :(得分:0)

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

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

答案 36 :(得分:0)

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

答案 37 :(得分:0)

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

答案 38 :(得分:0)

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

  1. 如果您有250列,并希望(确实)选择全部,请使用select *如果您想在同一天回家:)
  2. 如果您的编码需要灵活性并且需要的表很小,请再次选择*帮助您更快地编码并使其更容易维护。
  3. 如果您需要强大的工程和性能:
    • 如果他们只是少数几个,或
    • ,请写​​下您的列名
    • 编写一个工具,让您轻松选择/生成列名称
  4. 根据经验,当我需要选择所有列时,我会使用“select *”,除非我有一个非常具体的理由不这样做(另外,我认为在有很多很多列的表上更快) / p>

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

答案 39 :(得分:0)

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

答案 40 :(得分:0)

如果您关心速度,请确保使用预备语句。否则我与ilitirit一起改变就是你保护自己免受伤害。

/阿伦

答案 41 :(得分:0)

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

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

答案 42 :(得分:0)

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

答案 43 :(得分:0)

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

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

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

答案 44 :(得分:0)

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

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

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

答案 45 :(得分:0)

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

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

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

答案 46 :(得分:-1)

如果记录正在通过互联网,则可以通过限制返回的列来获得巨大的性能提升。

答案 47 :(得分:-2)

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