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

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

SELECT * FROM TABLE

or

SELECT column1, colum2, column3, etc. FROM TABLE

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

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

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

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


明确地定义列,因为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,那么限制返回的列可以大大提高性能。


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

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

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

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

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


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

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

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

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


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

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


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


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

/艾伦


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

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


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


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


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

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

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


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


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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

Another issue that occurs when using select * is that there are idiots who choose to add new fields in the middle fo the table (always a bad practice), if you use select * as the basis for an insert then suddenly your column order may be wrong and you may try to insert the social security number into the honorarium (the amoutn of money a speaker may get paid to pick a non-random example) which could be a very bad thing for data integrity. Even if the select isn't an insert, it looks bad to the customer when the data is suddenly in the worng order on the report or web page.

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


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

These are special cases like views or stored procedures where you want changes in underlying tables to propagate without needing to go and change every view and stored proc which uses the table. Even then, this can cause problems itself, like in the case where you have two views which are joined. One underlying table changes and now the view is ambiguous because both tables have a column with the same name. (Note this can happen any time you don't qualify all your columns with table prefixes). Even with prefixes, if you have a construct like:

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

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


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

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

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


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

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

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

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


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


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


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

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

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

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


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

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


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

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

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


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

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

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


The SELECT * might be ok if you actually needed all of the columns - but you should still list them all individually. You certainly shouldn't be selecting all rows from a table - even if the app & DB are on the same server or network. Transferring all of the rows will take time, especially as the number of rows grows. You should have at least a where clause filtering the results, and/or page the results to only select the subset of rows that need to be displayed. Several ORM tools exist depending on app language you are using to assist in querying and paging the subset of data you need. For example, in .NET Linq to SQL, Entity Framework, and nHibernate all will help you with this.


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


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

Selecting more data than you need makes the query less efficient - the server has to read and transfer extra data, so it takes time and creates unnecessary load on the system (not only the network, as others mentioned, but also disk, CPU etc.). Additionally, the server is unable to optimize the query as well as it might (for example, use covering index for the query). After some time your table structure might change, so SELECT * will return a different set of columns. So, your application might get a dataset of unexpected structure and break somewhere downstream. Explicitly stating the columns guarantees that you either get a dataset of known structure, or get a clear error on the database level (like 'column not found').

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


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

The most significant practical reason is that it forces the user to magically know the order in which columns will be returned. It's better to be explicit, which also protects you against the table changing, which segues nicely into... If a column name you're using changes, it's better to catch it early (at the point of the SQL call) rather than when you're trying to use the column that no longer exists (or has had its name changed, etc.) Listing the column names makes your code far more self-documented, and so probably more readable. If you're transferring over a network (or even if you aren't), columns you don't need are just waste.


上面所有人说的,加上:

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

SELECT foo, bar FROM widgets;

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


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

It's not like listing columns in SQl server is hard or even time-consuming. You just drag them over from the object browser (you can get all in one go by dragging from the word columns). To put a permanent performance hit on your system (becasue this can reduce the use of indexes and becasue sending unneeded data over the network is costly) and make it more likely that you will have unexpected problems as the database changes (sometimes columns get added that you do not want the user to see for instance) just to save less than a minute of development time is short-sighted and unprofessional.


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

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

如果显式列出了名称,那么通过所有存储过程、视图等查找对该列的每个引用就很简单了。只需为您的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 *比所有列都快。


总之,至少在PostgreSQL中,选择所有带*和不带*的列的性能几乎是一样的。

在PostgreSQL中,我创建了包含10个id_x列和1000万行的测试表,如下所示:

CREATE TABLE test AS SELECT generate_series(1, 10000000) AS id_1,
                            generate_series(1, 10000000) AS id_2,
                            generate_series(1, 10000000) AS id_3,
                            generate_series(1, 10000000) AS id_4,
                            generate_series(1, 10000000) AS id_5,
                            generate_series(1, 10000000) AS id_6,
                            generate_series(1, 10000000) AS id_7,
                            generate_series(1, 10000000) AS id_8,
                            generate_series(1, 10000000) AS id_9,
                            generate_series(1, 10000000) AS id_10;

然后,我交替运行以下2个查询共20次。*每个查询总共运行10次:

SELECT * FROM test:
SELECT id_1, id_2, id_3, id_4, id_5, id_6, id_7, id_8, id_9, id_10 FROM test;

结果> <

Select all columns with * Select all columns without *
1st run 12.792 seconds 12.483 seconds
2nd run 12.803 seconds 12.608 seconds
3rd run 12.537 seconds 12.549 seconds
4th run 12.512 seconds 12.457 seconds
5th run 12.570 seconds 12.487 seconds
6th run 12.508 seconds 12.493 seconds
7th run 12.432 seconds 12.475 seconds
8th run 12.532 seconds 12.489 seconds
9th run 12.532 seconds 12.452 seconds
10th run 12.437 seconds 12.477 seconds
Average 12.565 seconds 12.497 seconds

选择所有列的平均值:

*是12.565秒。 没有*是12.497秒。