在SQL Server 2005中“select * from table”vs“select colA,colB,etc from table”

时间:2008-11-26 17:14:52

标签: sql sql-server sql-server-2005 tsql views

为一篇冗长的帖子道歉,但我需要发布一些代码来说明问题。

受问题* What is the reason not to use select ?的启发,我决定指出一些我前段时间注意到的选择*行为的观察结果。

让我们的代码说明一切:

IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[starTest]') AND type in (N'U'))
DROP TABLE [dbo].[starTest]
CREATE TABLE [dbo].[starTest](
    [id] [int] IDENTITY(1,1) NOT NULL,
    [A] [varchar](50) NULL,
    [B] [varchar](50) NULL,
    [C] [varchar](50) NULL
) ON [PRIMARY]

GO

insert into dbo.starTest(a,b,c)
select 'a1','b1','c1'
union all select 'a2','b2','c2'
union all select 'a3','b3','c3'

go
IF  EXISTS (SELECT * FROM sys.views WHERE object_id = OBJECT_ID(N'[dbo].[vStartest]'))
DROP VIEW [dbo].[vStartest]
go
create view dbo.vStartest as
select * from dbo.starTest
go

go
IF  EXISTS (SELECT * FROM sys.views WHERE object_id = OBJECT_ID(N'[dbo].[vExplicittest]'))
DROP VIEW [dbo].[vExplicittest]
go
create view dbo.[vExplicittest] as
select a,b,c from dbo.starTest
go


select a,b,c from dbo.vStartest
select a,b,c from dbo.vExplicitTest

IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[starTest]') AND type in (N'U'))
DROP TABLE [dbo].[starTest]
CREATE TABLE [dbo].[starTest](
    [id] [int] IDENTITY(1,1) NOT NULL,
    [A] [varchar](50) NULL,
    [B] [varchar](50) NULL,
    [D] [varchar](50) NULL,
    [C] [varchar](50) NULL
) ON [PRIMARY]

GO

insert into dbo.starTest(a,b,d,c)
select 'a1','b1','d1','c1'
union all select 'a2','b2','d2','c2'
union all select 'a3','b3','d3','c3'

select a,b,c from dbo.vExplicittest
select a,b,c from dbo.vStartest

如果执行以下查询并查看最后2个select语句的结果, 您将看到的结果如下:

select a,b,c from dbo.vExplicittest
a1  b1  c1
a2  b2  c2
a3  b3  c3

select a,b,c from dbo.vStartest
a1  b1  d1
a2  b2  d2
a3  b3  d3

正如您在从dbo.vStartest 中选择a,b,c的结果中所见,列c的数据已被替换为colum d中的数据。

我认为这与编译视图的方式有关,我的理解是列由列索引(1,2,3,4)映射而不是名称。

我认为我会将其发布为对在其SQL中使用select *并遇到意外行为的人发出警告。

注意:如果在每次修改表后重建使用select *的视图,它将按预期工作。

2 个答案:

答案 0 :(得分:16)

sp_refreshview修复视图,或在视图定义中使用WITH SCHEMABINDING

  

如果未使用创建视图   SCHEMABINDING子句,sp_refreshview   应该在进行更改时运行   视图底层的对象   影响视图的定义。   否则,视图可能会产生   查询时出现意外结果。

答案 1 :(得分:2)

对于任何 RDBMS下的视图而言,这是非常标准的行为,而不仅仅是MSSQL,以及必须谨慎对待包含“select * from”的视图的使用的原因。

SQL引擎将编译每个视图 - 这基本上是字典/解析步骤并存储结果。如果因此更改基础表,则总是需要显式重新编译,除非数据库有一些标记视图的方法,以便在这种情况下进行检查。

该问题也可能(也将)也适用于存储过程和类似的数据库对象。