哪个更快/最好? SELECT *或SELECT column1,colum2,column3等
我听说SELECT *
在编写SQL命令时通常是不好的做法,因为SELECT
专门需要的列效率更高。
如果我需要SELECT
表中的每一列,我应该使用
SELECT * FROM TABLE
要么
SELECT column1, colum2, column3, etc. FROM TABLE
在这种情况下效率真的很重要吗? 如果你真的需要所有的数据,我会认为SELECT *
会在内部更加优化,但是我没有真正理解数据库。
我很想知道这种情况下的最佳做法。
更新:我可能应该指定唯一的情况,我真的想做一个SELECT *
是当我从一个表中select数据,我知道所有的列将永远需要检索,即使添加新的列。
鉴于我已经看到的反应,但这仍然是一个坏主意, SELECT *
不应该用于更多的技术原因,我曾经经历过。
select特定列更好的一个原因是它提高了SQL Server可以从索引访问数据而不是查询表数据的可能性。 这是我写的一篇文章: http : //weblogs.asp.net/jgalloway/archive/2007/07/18/the-real-reason-select-queries-are-bad-index-coverage.aspx
因为任何使用数据的代码都将获得相同的数据结构,而不pipe你将来对表模式做出什么样的改变。
鉴于您的规格,您正在select所有列,目前没有什么区别。 但是,意识到数据库模式确实会改变。 如果您使用SELECT *
您将获得添加到表中的新列,即使极有可能,您的代码也不准备使用或呈现新数据。 这意味着您正在将系统暴露给意外的性能和function更改。
你可能愿意把这个作为一个小小的代价来解决,但是要意识到你不需要的专栏必须是:
- 从数据库中读取
- 通过networking发送
- 统一到你的过程中
- (用于ADOtypes的技术)保存在内存中的数据表中
- 忽略和丢弃/垃圾收集
项目#1有许多隐藏的成本,包括消除一些潜在的覆盖索引,导致数据页面加载(和服务器caching抖动),招致行或页面/表锁,否则可能会被避免。
平衡这与指定列与*
的潜在节省,唯一的潜在节省是:
- 程序员不需要重新访问SQL来添加列
- SQL的networking传输更小/更快
- SQL Server查询parsing/validation时间
- SQL Server查询计划caching
对于第1项,实际情况是,您将添加/更改代码以使用您可能添加的任何新列,所以这是一个洗涤。
对于第2项来说,差异很难将您推入不同的数据包大小或数量的networking数据包。 如果你到了SQL语句传输时间是主要问题的地步,你可能需要首先降低语句的速度。
对于第3项来说,没有任何节省,因为无论如何扩展*
都意味着无论如何都意味着查询表格模式。 实际上,列出列将产生相同的成本,因为它们必须根据模式进行validation。 换句话说,这是一个彻底的洗涤。
对于第4项,当您指定特定的列时,查询计划caching可能会变大,但前提是处理的是不同的列集(这不是您指定的)。 在这种情况下,您需要不同的caching条目,因为您需要不同的计划。
所以,由于您指定问题的方式,这一切都会因为最终的架构修改而降低到问题的弹性。 如果你把这个模式刻录到ROM中,那么*
是完全可以接受的。
然而,我的一般指导方针是,你只应该select你需要的列,这意味着有时它看起来像你要求所有这些,但DBA和模式的演变意味着一些新的列可能会显着影响查询。
我的build议是,你应该总是select特定的列 。 记住,你一遍又一遍地善于处理你的事情,所以只要养成这样做的习惯。
如果您想知道为什么架构可能会在没有更改代码的情况下发生变化,请考虑审计日志logging,有效/过期date以及DBA为了遵从性问题而添加的其他类似事项。 隐藏的变化的另一个来源是在系统或用户定义的字段中的别处的性能的非规范化。
您应该只select您需要的列。 即使你需要所有列,列出列名仍然更好,这样sql服务器不必查询系统表中的列。
另外,如果有人在表中添加列,应用程序可能会中断。 你的程序会得到它没有期望的列,也可能不知道如何处理它们。
除此之外,如果表中有一个二进制列,那么查询会慢得多,并使用更多的networking资源。
select *
有四大原因是一件坏事:
-
最重要的实际原因是迫使用户神奇地知道列将被返回的顺序。 最好是明确的,这也可以保护你免受餐桌上的变化,很好地进入…
-
如果您正在使用的列名称发生更改,最好先赶上(在SQL调用时),而不是尝试使用不再存在的列(或名称已更改等) )
-
列出列名使您的代码更加自我logging,因此可能更具可读性。
-
如果您通过networking进行传输(或者即使不是),那么您不需要的列也只是浪费。
指定列列表通常是最好的select,因为如果有人向列表添加/插入列,应用程序不会受到影响。
即使查询不是通过networking发送,SELECT *也是一个不好的做法。
- select更多的数据会导致查询效率降低 – 服务器必须读取和传输额外的数据,因此需要花费时间并在系统上创build不必要的负载(不仅如同其他人所述的networking,还包括磁盘,CPU等)。 )。 此外,服务器无法优化查询以及它可能(例如,使用覆盖索引查询)。
- 经过一段时间你的表结构可能会改变,所以SELECT *将返回一组不同的列。 所以,你的应用程序可能会得到一个意想不到的结构数据集,并打破下游的某个地方 明确指出列确保您获得已知结构的数据集,或者在数据库级别获得明确的错误(如“未find列”)。
当然,这对于一个小而简单的系统来说并不重要。
指定你需要的列总是更好的,如果你想一下,SQL不需要每次查询时都会想“wtf is *”。 最重要的是,以后某个人可能会在表中添加列,而这些列在查询中实际上并不需要,在这种情况下,通过指定所有列可以更好。
在性能方面,使用特定列的SELECT可以更快(不需要读取所有数据)。 如果您的查询确实使用了所有的列,那么使用显式参数的SELECT仍然是首选。 任何速度差异将基本上不明显,接近恒定时间。 有一天你的模式会改变,这是很好的保险,以防止由此造成的问题。
指定列名肯定是更快 – 对于服务器。 但如果
- 性能不是一个大问题 (例如,这是一个网站内容数据库,每个表中有数百,甚至数千,但不是数百万行); 和
- 您的工作是使用通用框架创build许多小型的类似应用程序 (例如面向公众的内容pipe理网站),而不是创build一个复杂的一次性应用程序; 和
- 灵活性是很重要的 (大量的每个站点的数据库模式的定制);
那么你最好坚持使用SELECT *。 在我们的框架中,大量使用SELECT *允许我们将一个新的网站托pipe内容字段引入到一个表格中,赋予它CMS的所有好处(版本控制,工作stream程/审批等),而只需触摸几点,而不是几十点。
我知道数据库领袖会恨我 – 继续向我投票 – 但在我的世界里,开发人员的时间很短,CPU周期也很丰富,所以我相应地调整了我所节约的和我所浪费的东西。
你应该只select你需要的字段,只有所需的数字,即
SELECT Field1, Field2 FROM SomeTable WHERE --(constraints)
在数据库之外,dynamic查询会面临注入攻击和格式错误的数据的风险。 通常,您可以使用存储过程或参数化查询来解决这个问题。 另外(尽pipe不是那么多问题),服务器每次执行dynamic查询时都必须生成一个执行计划。
明确定义列,因为SQL Server将不必在列上进行查找来拉取它们。 如果你定义了列,那么SQL可以跳过这一步。
与“select*”的问题是可能带来的数据,你真的不需要。 在实际的数据库查询期间,选定的列不会真正添加到计算中。 真正“沉重”的是数据传输到客户端,任何你不需要的列都只是浪费networking带宽,并增加了等待查询返回的时间。
即使你使用“select * …”所带的所有列,那也只是现在。 如果将来您更改了表格/视图布局并添加了更多列,那么即使您不需要这些列,也会开始将这些列纳入您的select中。
“select *”语句不好的另一点是视图创build。 如果使用“select *”创build视图,然后向表中添加列,那么视图定义和返回的数据将不匹配,您需要重新编译视图才能使其重新工作。
我知道编写一个“select *”是诱人的,因为我真的不喜欢手动指定查询中的所有字段,但是当你的系统开始发展的时候,你会发现花这个额外的时间是值得的/努力指定字段,而不是花费更多的时间和精力去除视图上的错误或优化应用程序。
很多好的理由在这里回答,这是另一个没有提到的。
明确指定列将有助于您进行维护。 在某些时候,您将要进行更改或故障排除,并发现自己在问“哪里出了问题”。
如果你有明确列出的名字,那么通过所有的存储过程,视图等find对该列的每一个引用是很简单的。 只需转储您的数据库架构的CREATE脚本,并通过文本search。
如果您使用*或列,select同样有效(就速度而言)。
不同的是关于记忆,而不是速度。 当您select多列时,SQL Server必须分配内存空间来为您提供查询,包括您请求的所有列的所有数据,即使您仅使用其中一个列。
在性能方面什么是重要的执行计划,这反过来严重依赖于你的WHERE子句和JOIN,OUTER JOIN等的数量…
对于你的问题只需使用SELECT *。 如果你需要所有的列,没有性能差异。
虽然明确列出列是好的performance,不要发疯。
所以,如果你使用所有的数据,请尝试SELECT *为简单起见(想象有很多列,做JOIN …查询可能会变得很糟糕)。 然后 – 测量。 与显式列出列名的查询进行比较。
不要推测性能, 衡量它!
当你有一些包含大数据的列(比如post或者文章的正文),并且在给定的查询中不需要显式列表时,显式列表是最有帮助的。 然后通过不返回它在您的答案数据库服务器可以节省时间,带宽和磁盘吞吐量。 您的查询结果也将更小,这对任何查询caching都有好处。
使用显式字段名称与*相比不是更快,当且仅当您需要获取所有字段的数据时。
你的客户端软件不应该依赖于返回的字段的顺序,所以这也是无稽之谈。
而且有可能(尽pipe不太可能)你需要使用所有的字段,因为你还不知道哪些字段存在(想想非常dynamic的数据库结构)。
使用明确的字段名称的另一个缺点是,如果它们中有很多,并且它们很长,那么使得阅读代码和/或查询日志变得更加困难。
所以规则应该是:如果你需要所有的字段,使用*,如果你只需要一个子集,明确地命名它们。
结果太大了。 从SQL引擎生成并发送结果到客户端的速度很慢。
作为通用编程环境的客户端不是也不应该被devise为过滤和处理结果(例如,WHERE子句,ORDER子句),因为行数可能是巨大的(例如数以百万计的行)。
只要你的列仍然存在(以任何顺序),那么命名你希望在你的应用程序中获得的每一列也能确保你的应用程序不会因为有人改变表而中断。
这取决于您的数据库服务器的版本,但现代版本的SQL可以caching计划。 我会说什么是最能维护你的数据访问代码。
一个更好的做法是明确指出你想要的列是因为表结构中未来可能的变化。
如果您正在使用基于索引的方法手动读取数据,以便使用查询结果填充数据结构,那么将来当您添加/删除列时,您将很难找出哪里出了问题。
至于什么更快,我会推迟给他人的专业知识。
与大多数问题一样,这取决于您想要达到的目标。 如果你想创build一个允许任何表中的所有列的数据库网格,那么“Select *”就是答案。 但是,如果您只需要某些列,并且不经常添加或删除查询中的列,则可以单独指定它们。
这还取决于您要从服务器传输的数据量。 如果其中一个列被定义为备忘录,graphics,blob等,并且不需要该列,则最好不要使用“Select *”,否则会得到一大堆数据希望和你的performance可能受到影响。
要添加其他人所说的内容,如果所选的所有列都包含在索引中,则将从索引中提取结果集,而不是从SQL中查找其他数据。
上面所说的每个人,加上:
如果您正在努力寻找可读的可维护代码,请执行以下操作:
SELECT foo,bar FROM小部件;
立即可读并显示意图。 如果你打这个电话,你知道你回来了。 如果窗口小部件只有foo和bar列,那么select*意味着您仍然需要考虑返回的内容,确认订单映射是否正确等。但是,如果窗口小部件有更多列,但是您只对foo感兴趣和酒吧,那么当你查询通配符时,你的代码会变得杂乱,然后只使用一些返回的东西。
并且记住,如果您有定义的内部联接,则不需要重复所有联接列中的数据。
这不像SQl服务器中的列列很难甚至耗时。 您只需从对象浏览器中拖动它们即可(通过从单词栏中拖动,即可完成所有操作)。 要在你的系统上build立一个永久的性能指标(因为这可以减less索引的使用,并且通过networking发送不需要的数据代价很高),并且更有可能在数据库改变的时候你会有意想不到的问题(有时候列会被添加你不希望用户看到的例子)只保存不到一分钟的开发时间是短视和不专业的。
绝对定义你想每次select的列。 没有理由不这样做,性能改进是非常值得的。
他们不应该给出select“select*”
如果你需要每一列,那么只需使用SELECT *,但要记住,订单可能会改变,所以当你消费的结果按名称访问它们而不是索引。
我会忽略关于如何得到列表的意见 – parsing和validation命名列的机会等于处理时间(如果不是更多)。 不要过早地优化;-)
在执行效率方面,我没有意识到任何显着的差异。 但是为了程序员的效率,我会写这些字段的名字
- 如果您需要按编号进行索引,或者如果您的驱动程序对BLOB值有趣,您需要明确的顺序
- 如果您需要添加更多的字段,则只需阅读所需的字段
- 如果拼写错误或重命名字段,而不是来自logging集/行的空值,则会出现sql错误
- 你可以更好地阅读正在发生的事情。
嘿,实用。 在实施和部署时,使用select *时进行原型devise并select特定的列。 从执行计划的angular度来看,两者在现代系统上都是相同的。 但是,select特定列限制了必须从磁盘检索的数据量,存储在内存中并通过networking发送。
最终最好的scheme是select特定的栏目。
也要记住变化。 今天,Select *只会select你需要的列,但是明天它也可以select我刚添加的varbinary(MAX)列而不告诉你,现在你也在检索所有3.18GB的二进制数据在桌上昨天。
让我们想想哪个更快。 如果你只能select你需要的数据,那么速度会更快。 但是在testing中,您可以根据业务需求提取所有数据来判断可以过滤哪些数据。