我一直向我的开发者讲述SELECT *
是邪恶的,应该像瘟疫那样避免。
有没有合理的案例?
我不是在谈论COUNT(*)
- 大多数优化者都可以解决这个问题。
修改
我在谈论生产代码。
我看到这个不好的做法的一个很好的例子是在存储过程中使用select *
的遗留asp应用程序,并使用ADO
循环返回的记录,但是通过索引获取列。您可以想象当在字段列表末尾之外的某处添加新字段时发生的情况。
答案 0 :(得分:45)
我很高兴在审核触发器中使用*
。
在这种情况下,它实际上可以证明是有益的,因为它将确保如果将额外的列添加到基表中,它将引发错误,因此不能忘记在审计触发器和/或审计表结构中处理此问题
(如dotjoe)我也很高兴在派生表和列表表达式中使用它。虽然我习惯性地反过来做这件事。
WITH t
AS (SELECT *,
ROW_NUMBER() OVER (ORDER BY a) AS RN
FROM foo)
SELECT a,
b,
c,
RN
FROM t;
我最熟悉SQL Server,并且至少优化器可以识别只需要列a,b,c
并且在内表表达式中使用*
不会导致任何问题不必要的开销检索和丢弃不需要的列。
原则上SELECT *
应该在视图中是正常的,并且它应该是视图中应该避免的最终SELECT
但是在SQL Server中这可能会导致问题,因为它存储列基础表更改时未自动更新的视图元数据,*
的使用可能导致混淆和错误的结果,除非运行sp_refreshview
来更新此元数据。
答案 1 :(得分:34)
在许多情况下,SELECT *是最佳解决方案。在Management Studio中运行即席查询只是为了了解您正在使用的数据。查询您不知道列名的表,因为这是您第一次使用新架构。构建一次性quick'n'dirty工具,进行一次性迁移或数据导出。
我同意在“正确”开发中,你应该避免它 - 但是有很多场景,“正确”开发不一定是业务问题的最佳解决方案。规则和最佳实践是很好的,只要你知道什么时候打破它们。 :)
答案 2 :(得分:28)
在使用CTE时,我会在生产中使用它。但是,在这种情况下,它并不是select *
,因为我已经在CTE中指定了列。我只是不想在最终选择中重新指定。
with t as (
select a, b, c from foo
)
select t.* from t;
答案 3 :(得分:25)
如果您在谈论实时代码,我无法想到。
人们说它使得添加列更容易开发(因此它们会自动返回并且可以在不更改存储过程的情况下使用)不知道编写最佳代码/ sql。
我只在编写不会被重用的即席查询时使用它(找出表的结构,当我不确定列名是什么时获取一些数据)。
答案 4 :(得分:16)
我认为在select *
子句中使用exists
是合适的:
select some_field from some_table
where exists
(select * from related_table [join condition...])
有些人喜欢在这种情况下使用select 1
,但它并不优雅,并且它不会购买任何性能改进(早期优化再次发生)。
答案 5 :(得分:7)
在生产代码中,我倾向于100%同意你。
但是,我认为*在执行即席查询时不仅仅证明了它的存在。
答案 6 :(得分:6)
你已经对你的问题得到了很多答案,但你似乎在解雇一切并非扼杀你想要听到的东西。不过,这是第三次(到目前为止)的时间:有时 没有瓶颈。有时表现比罚款要好。有时表格不断变化,修改每个SELECT查询只是管理可能不一致的一点。有时你必须按照不可能的时间表交付,这是你需要考虑的最后一件事。
如果您住在子弹时间,请确保输入所有列名称。但为何停在那里?在无架构的dbms中重写您的应用程序。好吧,在程序集中编写自己的 dbms。这真的显示了他们。
答案 7 :(得分:4)
请记住,如果你使用select *并且你有一个连接,那么至少会有一个字段被发送两次(连接字段)。这无缘无故地浪费了数据库资源和网络资源。
答案 8 :(得分:2)
作为一种工具,我用它来快速刷新我的记忆,以便我可以从查询中获得什么。作为生产级别查询本身..没办法。
答案 9 :(得分:2)
当创建一个处理数据库的应用程序时,比如phpmyadmin,你在一个显示完整表格的页面中,在这种情况下使用SELECT *
可以证明是合理的,我猜。
答案 10 :(得分:2)
关于我能想到的唯一一件事就是开发一个实用程序或SQL工具应用程序,该应用程序被编写为针对任何数据库运行。即便在这里,我倾向于查询系统表以获取表结构,然后从中构建任何必要的查询。
最近有一个地方,我的团队使用SELECT *
,我认为没关系...我们有一个数据库作为外观存在于另一个数据库(称为DB_Data),所以它主要是制作的对其他数据库中的表的视图。当我们生成视图时,我们实际生成了列列表,但是DB_Data数据库中有一组视图,这些视图是在将行添加到通用查找表时自动生成的(此设计在我到达之前已经到位)。我们编写了一个DDL触发器,以便在此过程中在DB_Data中创建视图时,会在外观中自动创建另一个视图。由于视图始终生成为与DB_Data中的视图完全匹配,并且始终刷新并保持同步,因此我们仅使用SELECT *
来简化。
如果大多数开发人员在没有合法使用生产代码SELECT *
的情况下完成整个职业生涯,我不会感到惊讶。
答案 11 :(得分:2)
phpmyadmin
的开发人员如何确保他们显示数据库表的所有字段?
答案 12 :(得分:2)
我使用select *来查询为读取而优化的表(非规范化,平面数据)。非常有利,因为表格的目的只是为了支持应用程序中的各种视图。
答案 13 :(得分:1)
可以想象您需要设计数据库和应用程序,以便可以向表中添加列而无需重写应用程序。如果您的应用程序至少检查列名称,则可以安全地使用SELECT *
并使用一些适当的默认操作处理其他列。当然,应用程序可以查询系统目录(或特定于应用程序的目录)以获取列信息,但在某些情况下,SELECT *
就是这样做的语法糖。
然而,存在明显的风险,并且为应用程序添加所需的逻辑以使其可靠可能仅仅意味着在不太合适的介质中复制数据库的查询检查。我不会推测现实生活中的成本和收益是如何权衡的。
在实践中,我坚持SELECT *
3个案例(其他答案中提到了一些案例:
EXISTS
谓词的内容。答案 14 :(得分:1)
我需要多次显示列名未知的表中的数据。所以我做了SELECT *
并在运行时获得了列名。
我收到了一个遗留应用程序,其中一个表有200列,一个视图有300个。SELECT *
的风险暴露并不比明确列出所有300列更糟糕。
答案 15 :(得分:1)
是的,但仅限于意图实际获取表中所有列的情况,而不是因为您希望表当前具有所有列。
例如,在我工作的一个系统中,我们有UDF(用户定义字段),用户可以在报告中选择他们想要的字段,顺序以及过滤。在构建结果集时,从我正在构建的临时表中简单地“选择*”而不是必须跟踪哪些列处于活动状态更有意义。
答案 16 :(得分:0)
如果您想查找所有列并希望订购,您可以执行以下操作(至少如果您使用MySQL):
SHOW COLUMNS FROM mytable FROM mydb;
(1)
您可以查看有关所有字段的所有相关信息。您可以防止类型问题,并且您可以确定所有列名称。这个命令非常快,因为你只要求表的结构。从结果中,您将选择所有名称,并将构建如下字符串:
"select " + fieldNames[0] + ", fieldNames[1]" + ", fieldNames[2] from mytable". (2)
如果您不想运行两个单独的MySQL命令,因为MySQL命令很昂贵,您可以将(1)和(2)包含到存储过程中,该存储过程将结果作为OUT参数,这样您就可以只需调用存储过程,每个命令和数据生成都将在数据库服务器上进行。
答案 17 :(得分:0)
Select *
在任何时候都是合理的:
为什么每次向表中添加字段时都需要返回并且不必担心更改相关存储过程的开销?
为什么我甚至不得不考虑我是否选择了正确的领域,而绝大多数时候我都想要他们中的大部分时间,而绝大多数时候我都没有还有什么东西是瓶颈?
如果我遇到特定的性能问题,那么我会回过头来解决这个问题。否则,在我的环境中,我只能进行过早(且昂贵)的优化。
编辑..在讨论之后,我想我会加上这个:
...而且人们还没有做过其他不受欢迎的事情,例如试图访问列(i),这可能会在其他情况下破坏:)
答案 18 :(得分:0)
取决于生产软件的背景。
如果您正在为表管理工具编写一个简单的数据访问层,用户将在其中选择表并在网格中查看结果,那么看起来* SELECT **就可以了。
换句话说,如果您选择通过其他方式处理“字段选择”(如在检索结果集后自动或用户指定的过滤器中),那么它似乎没问题。
另一方面,如果我们谈论某种具有业务规则,定义模式等的企业软件......那么我同意* SELECT **是一个坏主意。
编辑:哦,当源表是触发器或视图的存储过程时,“* SELECT **”应该没问题,因为您通过其他方式管理结果集(视图的定义或存储过程的结果集)
答案 19 :(得分:0)
我知道我参加派对的时间已经很晚了,但我知道我总是想要所有列而不管列名是什么,我会使用select *。这可能是一个相当边缘的情况,但在数据仓库中,我可能想要从第三方应用程序中分阶段整个表。我的标准流程是删除临时表并运行
select *
into staging.aTable
from remotedb.dbo.aTable
是的,如果远程表上的模式发生更改,下游依赖项可能会抛出错误,但无论如何都会发生错误。