为什么使用'*'来build立一个视图不好?

为什么使用'*'来build立一个视图不好?

假设你有一个复杂的连接,所有的字段都可以用在某个地方。

那么你只需要select所需的领域。

SELECT field1, field2 FROM aview WHERE ... 

“aview”视图可以是SELECT table1.*, table2.* ... FROM table1 INNER JOIN table2 ...

如果两个字段在table1和table2中具有相同的名称,则会出现问题。

这只是为什么在视图中使用“*”是不好的原因?

使用'*',您可以在不同的上下文中使用视图,因为信息在那里。

我错过了什么?

问候

我不认为有太多的软件是“坏”,但有很多东西是坏的方式滥用:-)

你给的例子是为什么*可能不会给你你所期望的,我认为还有其他的。 例如,如果基础表发生更改,可能会添加或删除列,则使用*的视图将继续有效,但可能会破坏使用它的任何应用程序。 如果您的视图明确指定了列,那么在更改模式时,有人更有可能发现问题。

另一方面,您可能实际上希望您的视图能够愉快地接受对基础表的所有更改,在这种情况下,*就是您想要的。

更新:我不知道OP是否有一个特定的数据库供应商,但现在很清楚,我的最后一句话并不适用于所有types。 我非常感激user12861和Jonny Leeds指出这点,对不起,我花了6年的时间来编辑我的答案。

尽pipe这里的许多评论都非常好,并且引用了在查询中使用通配符的一个常见问题,例如,如果基础表发生更改,将导致错误或不同的结果,但尚未涉及的另一个问题是优化。 拉取表的每一列的查询往往不如只拉取实际需要的列的查询效率。 当然,有些时候你需要每一列,这是一个主要的PIA必须引用它们,特别是在一个大的表中,但是如果你只需要一个子集,为什么你的查询会以比你需要的更多的列停滞。

* ”有风险的另一个原因,不仅在视图中,而且在查询中,是列可以更改名称或更改基础表中的位置。 使用通配符意味着您的视图容易适应这些更改而无需更改。 但是,如果您的应用程序在结果集中按位置引用列,或者如果使用返回按列名键值的结果集的dynamic语言,则可能会遇到难以debugging的问题。

我总是避免使用通配符。 这样,如果列更改名称,我立即在视图或查询中得到一个错误,我知道在哪里解决它。 如果某个列在底层表中改变了位置,那么在视图或查询中指定列的顺序就可以补偿这一点。

这些其他答案都有好处,但在SQL服务器上至less也有一些错误的观点。 尝试这个:

 create table temp (i int, j int) go create view vtemp as select * from temp go insert temp select 1, 1 go alter table temp add k int go insert temp select 1, 1, 1 go select * from vtemp 

SQL Server在添加时不了解“新”列。 取决于你想要什么,这可能是一件好事或一件坏事,但无论如何,依靠它可能不是好事。 所以避免它似乎是一个好主意。

对我来说,这种奇怪的行为是避免在视图中select*的最有说服力的理由。

这些评论告诉我,MySQL有类似的行为,Oracle不会(它会了解到对表的更改)。 这种不一致对我来说是更多的理由不使用select *在视图中。

使用'*'作任何生产是不好的。 对于一次性查询来说非常好,但是在生产代码中,您应该尽可能的明确。

对于特定的视图,如果基础表中添加或删除了列,则该视图将错误或中断,直到重新编译。

这是因为你并不总是需要每一个variables,而且还要确保你正在考虑你特别需要的东西。

例如,在您的站点上构build用户列表时,将所有哈希密码从数据库中取出是没有意义的,因此select*将会是徒劳的。

曾几何时,我用另一个数据库(在同一台服务器上)的表创build了一个视图

 Select * From dbname..tablename 

然后有一天,一个列被添加到目标表。 视图开始返回完全不正确的结果,直到重新部署。


完全不正确:没有行。

这是在Sql Server 2000上。

我推测这是因为视图捕获的syscolumns值,即使我使用*。

如果在视图之外不使用列,那么在视图内使用SELECT *不会产生太多的性能开销 – 优化器将优化它们; SELECT * FROM TheView可能会浪费带宽,就像在任何时候通过networking连接拉动更多列一样。

事实上,我发现从我的数据仓库中的大量表中几乎所有列链接的视图根本没有引入任何性能问题,即使这些视图之外的相对较less的列是被请求的。 优化器可以很好地处理这个问题,并且能够将外部过滤条件向下推送到视图中。

但是,由于上面给出的所有原因,我很less使用SELECT *

我有一些业务stream程,在这些业务stream程中,大量的CTE是相互build立的,有效地从派生列的派生列构build派生列(当业务合理化和简化这些计算时,希望有一天会被重构),在这种情况下,我需要所有的列,每次都下降,而我使用SELECT * – 但是SELECT *不在基础层使用,只在第一个CTE和最后一个之间。

SQL查询基本上是由程序员devise的function单元,用于某些情况下。 对于长期的稳定性和可支持性(可能由你以外的其他人),一个function单元中的所有内容都应该在那里存在,而且它应该是合理的(或者形成文件)为什么在那里 – 尤其是每个数据元素。

如果我从现在开始两年来需要或希望改变你的疑问,我希望在我相信我能够把它弄糊涂之前,把它弄得很彻底。 这意味着我需要了解为什么所有的列被叫出来。 (如果你试图在多于一个的上下文中重用查询,这更显然是正确的。出于类似的原因,这通常是个问题。)如果我在输出中看到不能涉及某个目的的列,我很确定我不明白它做了什么,为什么,以及改变它的后果是什么。

使用*通常是一个糟糕的主意。 一些代码authentication引擎将其标记为警告,并build议您仅明确指出必要的列。 *的使用可能会导致性能下降,因为您可能只需要一些列而不是全部。 但是,另一方面,在某些情况下,使用*是理想的。 想象一下,无论如何,使用你提供的例子,对于这个视图(aview),你总是需要这些表中的所有列。 将来,添加列时,您不需要更改视图。 这可以是好的或坏的,这取决于你正在处理的情况。

我认为这取决于你使用的语言。 当语言或DB驱动程序返回结果的字典(Python,Perl等)或关联数组(PHP)时,我更喜欢使用select *。 它使得你的代码更容易理解,如果你是通过名称来引用列而不是数组中的索引。

其他人似乎没有提到它,但在SQL Server中,您还可以使用schemabinding属性设置您的视图。

这可以防止修改任何影响视图定义的基表(包括删除它们)。

这在某些情况下可能对您有用。 我意识到我并没有完全回答你的问题,但我想我会强调它。

SQL Server的情况实际上比@ user12861的答案还要糟糕,这意味着:如果对多个表使用SELECT * ,向查询中早期引用的表中添加列实际上会导致您的视图返回新列下的值老专栏的幌子。 看下面的例子:

 -- create two tables CREATE TABLE temp1 (ColumnA INT, ColumnB DATE, ColumnC DECIMAL(2,1)) CREATE TABLE temp2 (ColumnX INT, ColumnY DATE, ColumnZ DECIMAL(2,1)) GO -- populate with dummy data INSERT INTO temp1 (ColumnA, ColumnB, ColumnC) VALUES (1, '1/1/1900', 0.5) INSERT INTO temp2 (ColumnX, ColumnY, ColumnZ) VALUES (1, '1/1/1900', 0.5) GO -- create a view with a pair of SELECT * statements CREATE VIEW vwtemp AS SELECT * FROM temp1 INNER JOIN temp2 ON 1=1 GO -- SELECT showing the columns properly assigned SELECT * FROM vwTemp GO -- add a few columns to the first table referenced in the SELECT ALTER TABLE temp1 ADD ColumnD varchar(1) ALTER TABLE temp1 ADD ColumnE varchar(1) ALTER TABLE temp1 ADD ColumnF varchar(1) GO -- populate those columns with dummy data UPDATE temp1 SET ColumnD = 'D', ColumnE = 'E', ColumnF = 'F' GO -- notice that the original columns have the wrong data in them now, causing any datatype-specific queries (eg, arithmetic, dateadd, etc.) to fail SELECT * FROM vwtemp GO -- clean up DROP VIEW vwTemp DROP TABLE temp2 DROP TABLE temp1 

如果你有连接使用select *自动意味着你正在返回更多的数据比你所需要的连接字段中的数据重复。 这是数据库和networking资源的浪费。

如果你足够天真地使用调用其他视图的视图,使用select *可以使他们更糟糕的表演者(这是对自身性能不好的技术,调用你不需要的多列使得​​它变得更糟)。