为什么SQL Server视图需要定期刷新

13

为什么我需要编写“刷新视图”脚本,并在每次添加或编辑视图字段后执行它们?

SQL Server理解当在Management Studio的高级视图编辑窗口中编辑视图时,需要刷新视图。那么,为什么不能在通过脚本编辑视图后,直接告诉视图去刷新自己呢?

3个回答

12

如果底层表发生任何变化,视图就需要进行刷新。这可能会更改视图列的数据类型或重新排列其索引。因此,它需要知道这些变化。否则,您将对其运行查询,并且它会很快崩溃。

更改视图时不必运行sp_refreshview,只需更改其基础表即可。

另外,请不要挑逗快乐球。

编辑:我连续运行了此代码,试图复制您的问题。遗憾的是,我无法复制它,因为它在预期中正常工作(SQL Server 2008):

create view MyView
as
select ProductKey, ProductID, ProductName, Price
from dbo.Products

select v.* from MyView v

alter view MyView
as
select ProductKey, ProductID, ProductName, Price*100 as MyPrice
from dbo. Products

select v.* from MyView v

1
但是,当我有类似 SELECT b.* FROM b 的东西时,这种行为也会发生。在向 b 添加列之后,视图尝试显示旧列,即使它们没有硬编码。 - Jan Jongboom
2
Eric的评论仍然适用。每当基础表的架构发生更改时,视图的元数据都需要刷新,即使视图的代码本身仍然正确。 - TimothyAWiseman

6

在视图定义中使用WITH SCHEMABINDING,以消除任何刷新的需要

并与ALTER VIEW结合使用,而不是使用设计师

编辑,2012年7月,来自上面的链接。我加粗了

SCHEMABINDING

将视图绑定到底层表的模式或多个表的模式。当指定了 SCHEMABINDING 时,基本表或多个表不能以影响视图定义的方式进行修改。必须先修改或删除视图定义,以消除对要修改的表的依赖关系。使用 SCHEMABINDING 时,select_statement 必须包括引用的表、视图或用户定义函数的两部分名称(schema.object)。所有引用的对象必须在同一数据库中。

使用 SCHEMABINDING 创建的视图或表不能被删除,除非删除该视图或更改该视图以使其不再具有模式绑定。否则,数据库引擎会引发错误。此外,在影响视图定义的情况下,对参与视图的表执行 ALTER TABLE 语句会失败。


4
我犹豫是否要提出这个建议。只有当表都在同一数据库且位于同一服务器上时,使用“WITH SCHEMABINDING”才有效。 - Eric
1
使用schemabinding可以避免因为防止底层表格被更改而需要进行任何刷新。如果您必须更改底层表,则最好的方法是在删除带有schemabinding的选项以进行更改后,提醒您需要更新视图。 - TimothyAWiseman
1
我不明白完全防止更改如何等同于消除刷新的需要?除非我误解了,使用WITH SCHEMABINDING将防止基础表被更改? - ErikE

2

我曾经遇到过表格更改的同样问题。真正的解决方案是使用DDL触发器来修改表格:

Create Trigger RefreshViewTrigger On Database FOr Alter_Table As
Declare @tname as nvarchar(256), @sql nvarchar(400);
Select @tname = EVENTDATA().value('(/EVENT_INSTANCE/SchemaName)[1]','nvarchar(100)')  + '.' +  EVENTDATA().value('(/EVENT_INSTANCE/ObjectName)[1]','nvarchar(100)');
Declare k cursor For Select distinct 'sp_refreshview ''' + o.name + '''' sql
    From sys.objects o Join sys.sql_expression_dependencies s On o.object_id = s.referencing_id   
    Where o.type = 'V' AND s.referenced_id = Object_id(@tname);  
Open k
Fetch Next from k into @sql
While @@FETCH_STATUS = 0
Begin
    Print( @sql )
    EXEC( @sql )
    Fetch Next from k into @sql
End
Close k
Deallocate k
Go

我在2008 R2上工作,甚至可能是早期版本。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接