出于习惯,我从不在生产代码中使用SELECT *(我只在特殊的废品查询中使用它,通常是在学习对象的模式时使用)。使用它,但如果这样做我会觉得便宜。

我的用例是在存储过程中,在该存储过程中,将创建一个本地临时表,该临时表应始终与用于创建该表的基础表匹配。临时表将在稍后填充,因此快速创建temp表而又不会引起冗长的技巧将是SELECT * INTO #TempTable FROM RealTable WHERE 1 = 0,特别是对于具有数百个列的表。

如果存储过程的使用者是不可知的到动态结果集,那么我将服务出售给SELECT *会有任何问题吗?

#1 楼

我通常在生产代码中讨厌SELECT *,而且我一直在使用SELECT *导致大量返工。您的案例确实看起来像是在合理使用。

我发现SELECT *是必须的地方-它的邪恶堂兄“ INSERT INTO tbl”没有列列表-正在归档中。行被移动到必须具有相同结构的另一个表的情况。

INSERT INTO SalesOrderArchive  -- Note no column list
SELECT *
  FROM SalesOrder
 WHERE OrderDate < @OneYearAgo

DELETE FROM SalesOrder
 WHERE OrderDate < @OneYearAgo


如果将来在SalesOrder中添加了新列,但未在SalesOrderArchive中添加,则INSERT将失败。听起来不错,但这实际上是一件好事!因为替代方案要差得多。如果所有列都列在INSERT和SELECT上,则INSERT将成功,随后的DELETE也将成功(实际上是“ DELETE *”)。成功的生产代码不会受到任何关注,并且可能需要很长的时间才能有人注意到新列没有被存档,而是被完全删除。

#2 楼


在生产中,select *有什么用??



create table #foo(a int, b int, c int, d int)
...
select * from #foo


,即,当*绑定到在同一批次中声明的显式列列表时,仅用于避免多次重复列列表。

*引用表或视图时,例如,在这里,有关缓存的元数据会有一些令人讨厌的复杂性。它并不能真正节省您的输入,因为SSMS允许您拖放完整的列列表。

评论


我认为这都不是一个好用例,在这里使用SELECT *是懒惰的。如果查询或表发生更改,您仍然可能会遇到问题。我希望显式更改SELECT,即您的API。

–way0utwest
20年1月1日,下午2:26

#3 楼

当由SELECT *引入EXISTS时,就会有效使用它。如果代码在内部,则添加例如

相关的问答:EXISTS(SELECT 1 ...)vs EXISTS(SELECT * ...)一个或另一个?

另请参见:<不好的习惯:使用SELECT * /忽略Aaron Bertrand的列列表。

选择时* Erik Darling没关系。


#4 楼

我将大胆地说出来:生产代码中有SELECT *的用例。任何时候只要您说“我希望对表的任何更改都可以立即反映在对我的结果输出的更改中”,就是这样做的一种情况。

让我举几个例子:


用例1-制作一个镜像主表的视图,除了它可以过滤掉敏感的公司专用数据。

在这种情况下,您需要该视图选择 *。输出应该被认为是对主表的反映。输出布局匹配
表布局是功能,而不是错误。


...


用例# 2-制作一个存储的proc,将要更新的一些记录复制到临时保存表中,以防进程
遇到问题(有点麻烦)。

在这种情况下,输出与表本身不匹配的情况很糟糕
-这意味着您可能无法使用
临时保存表中的数据返回到起点。


评论


Re:用例1:在SQL Server中,如果视图执行SELECT * FROM dbo.A(在最高级别),然后将一列添加到dbo.A,则新列将不会自动包含在视图中。您将必须运行sp_refreshview系统SP或发出具有相同视图定义的ALTER VIEW,新列才能出现在输出中。至于用例#2,说实话,我不确定我是否了解这种情况,但是也许我是唯一一个不知道那件事的人,所以不必为可怜的老我详述一下:)

– Andriy M
19年11月23日15:24



我不会将案例2称为“生产代码”。是的,DBA在管理任务中使用“选择*”,最终用户一直在使用它来报告。

– David Browne-微软
19年11月23日15:30

#5 楼


选择*在生产中有什么好的用途?


真的没有。在开发过程中,您提到的方式(选择前n *个)很有意义,但否则会养成不良习惯,并可能导致问题。

您已经谈到了为什么不应该使用它的要点,那就是实际表的结构可能会改变。像上面提到的那样创建一个临时表是一件好事,但是在以后的过程中,可能会导致问题,在您使用一些INSERT命令填充临时表之后,返回带有SELECT *的结果集。现在,您的最终应用程序将检索意外的列。

您也可以使用SELECT ... INTO #TEMP FROM ...快速创建临时表。很难知道哪种方法最适合您的情况。

SELECT *的其他大多数问题似乎与您的用例无关紧要


视图(当表更改时可能会中断)
绑定问题
表扫描(因为您实际上确实想要所有列)
检索不必要的列(因为您似乎再次想要它们)顺序位置


#6 楼

我对您的问题的回答是“最多/很多用例”

您的用例着重说明*为何不可怕。
您的架构将会改变。
由于需要添加字段,为什么要设置自己以接触每个SP?

如果要添加字段,为什么我的UI会在乎?
如果要删除字段,则使用*或CSV都无关紧要,这意味着要进行重大更改。

”如果我的存储过程的使用者与动态结果无关集,...“

这就是使用select *的真正问题。如果您的消费者写得不好,那么您可能会遇到问题。
例如,如果您将Fields [13]格式化为日期...

在某些情况下,我会回避选择*:

缓解延迟-我的使用者很远,他们只需要表中相对较小的字段子集

联接-涉及多个表的复杂查询。消费者可能不需要所有表中的所有字段。实际上,有重复的键列可能应该省略。

我知道我的使用者编写的代码很差-如果您正在开发公共API,我想您有可能希望兑现OpenClose并使其每当字段集更改时,都会使用一个新的api方法。对我来说,这似乎是解决上述问题的一种不好的方法。
总是有象牙塔套装。开放的心态聆听他们的想法。
然后下定决心。

#7 楼



如果添加新列后,始终可以安全地忽略它(例如:从id = @ x的客户中选择名字,姓氏),则永远不会使用select *-您触摸的列越多,发现/创建有用索引的机会就越少。

如果添加新列时,将其静默丢弃将是不好的(任何类型的数据复制),然后使用未指定的select(插入到archiveTable select * from the Table where isOld = true)中的代码这里的失败不是错误,它是一个功能-尤其是在您同时控制数据库和读取表的代码的情况下。

这里的失败机制是不好的-您不会如果您要向此人添加新的喜欢的颜色,则希望您的名字查找失败。

如果您在编写存档代码后添加了该列,则您不想忽略对该人的喜欢的颜色进行存档。

关于连接的说明-sql server将跳过读取以后不使用的任何列

select firtname,email from (select * from profile where isArchived=false)p join (select * from emailaddresses where mostRecentSend < ago(6days))e on p.id=e.profileId


除了名字,id和电子邮件列。