如果我的 table 定义更新了,为什么视图没有更新?
why view is not updated if my table definition is updated?
假设我有一个 table 定义如下:
CREATE TABLE Test
(
a INT,
b INT
)
之后,我在 table 上创建了一个视图,
CREATE VIEW ViewTest
AS
SELECT * FROM Test
之后,当我 运行 查看查询时,它 return 我有两列,即 A & B
.
而且,后来我更新了 table 的定义并在其中插入了一个新列:
ALTER TABLE Test ADD c INT
但是,现在当我 运行 再次查看它时 return 是视图语句,它 return 我的列数相同,现在是三列。
我只想知道为什么?因为我使用了 Select * 语句,所以每次它都应该 return 我用整个列。
当您向测试添加新列时,ViewTest 已经存在,并且只有列 A 和 B。您必须删除 ViewTest 并为 "SELECT *" 语句重新创建它以检索新列C.
来自 MSDN 文档:
创建一个虚拟的 table,其内容(列和行)由查询定义。使用此语句在数据库中的一个或多个 table 中创建数据视图。例如,视图可用于以下目的:
- 集中、简化和自定义每个用户对数据库的看法。
- 作为一种安全机制,允许用户通过视图访问数据,而不授予用户直接访问基础库的权限 tables。
- 提供向后兼容的接口来模拟架构已更改的 table。
View Definition 文档中的这棵树应该会回答你为什么。最精确的是它的第 3 个。
使用 select *
创建视图也不是一个好习惯,因为您或查看该视图的任何其他人都不知道它有哪些列。
该文档上还有一条注释:
备注
Any updates performed directly to a view's underlying tables are not verified against the view, even if CHECK OPTION is specified.
创建视图时,它会将视图定义作为元数据存储在系统 table 中。即使您使用 SELECT * FROM
它也会存储确切的列名,例如SELECT a, b FROM
如果您随后更新基础 table,视图的元数据定义仍然保持不变,因此不会选取任何新列。
您需要删除并重新创建视图或 运行 sp_refreshview 更新定义
当您第一次遇到它时,这确实像是意想不到的行为。它有据可查。例如,在 CREATE VIEW
的文档中:
If a view is not created with the SCHEMABINDING clause, sp_refreshview
should be run when changes are made to the objects underlying the view
that affect the definition of the view. Otherwise, the view might
produce unexpected results when it is queried.
重新编译很容易。 . .您可以使用 alter view
或 sp_refreshview
(已记录 here)。
两个选项是:
- 使用 SCHEMABINDING 定义视图以防止 更改视图中使用的表。
- 在表更改后手动修改视图。
我怀疑这是 SQL 服务器中的优化,因此当您使用视图时,引擎可以只插入编译代码,而不是对正在使用的表进行一堆完整性检查。这种优化对于事务处理中使用的视图很重要。如果您通过视图进行 运行 更复杂的查询,这并不重要。但是,这并不能解释为什么当基础表发生变化时不进行检查。
过去,当基础表发生更改并且生成的 select
的列偏移量错误时,我曾以一种糟糕的方式被它咬伤。请注意,仅通过避免 select *
,此问题 未 得到解决,尽管这通常是一个很好的做法。
此外,如果您有一个定期运行的大型系统(例如,每周或每天),您可能希望放置一个重新编译系统中所有视图的作业。这也确保了他们的执行计划正在更新表的最新统计信息。而且,如果您真的要小心,请使用 SCHEMABINDING
,因此需要有意识地对基础表进行任何更改。
假设我有一个 table 定义如下:
CREATE TABLE Test
(
a INT,
b INT
)
之后,我在 table 上创建了一个视图,
CREATE VIEW ViewTest
AS
SELECT * FROM Test
之后,当我 运行 查看查询时,它 return 我有两列,即 A & B
.
而且,后来我更新了 table 的定义并在其中插入了一个新列:
ALTER TABLE Test ADD c INT
但是,现在当我 运行 再次查看它时 return 是视图语句,它 return 我的列数相同,现在是三列。
我只想知道为什么?因为我使用了 Select * 语句,所以每次它都应该 return 我用整个列。
当您向测试添加新列时,ViewTest 已经存在,并且只有列 A 和 B。您必须删除 ViewTest 并为 "SELECT *" 语句重新创建它以检索新列C.
来自 MSDN 文档:
创建一个虚拟的 table,其内容(列和行)由查询定义。使用此语句在数据库中的一个或多个 table 中创建数据视图。例如,视图可用于以下目的:
- 集中、简化和自定义每个用户对数据库的看法。
- 作为一种安全机制,允许用户通过视图访问数据,而不授予用户直接访问基础库的权限 tables。
- 提供向后兼容的接口来模拟架构已更改的 table。
View Definition 文档中的这棵树应该会回答你为什么。最精确的是它的第 3 个。
使用 select *
创建视图也不是一个好习惯,因为您或查看该视图的任何其他人都不知道它有哪些列。
该文档上还有一条注释:
备注
Any updates performed directly to a view's underlying tables are not verified against the view, even if CHECK OPTION is specified.
创建视图时,它会将视图定义作为元数据存储在系统 table 中。即使您使用 SELECT * FROM
它也会存储确切的列名,例如SELECT a, b FROM
如果您随后更新基础 table,视图的元数据定义仍然保持不变,因此不会选取任何新列。
您需要删除并重新创建视图或 运行 sp_refreshview 更新定义
当您第一次遇到它时,这确实像是意想不到的行为。它有据可查。例如,在 CREATE VIEW
的文档中:
If a view is not created with the SCHEMABINDING clause, sp_refreshview should be run when changes are made to the objects underlying the view that affect the definition of the view. Otherwise, the view might produce unexpected results when it is queried.
重新编译很容易。 . .您可以使用 alter view
或 sp_refreshview
(已记录 here)。
两个选项是:
- 使用 SCHEMABINDING 定义视图以防止 更改视图中使用的表。
- 在表更改后手动修改视图。
我怀疑这是 SQL 服务器中的优化,因此当您使用视图时,引擎可以只插入编译代码,而不是对正在使用的表进行一堆完整性检查。这种优化对于事务处理中使用的视图很重要。如果您通过视图进行 运行 更复杂的查询,这并不重要。但是,这并不能解释为什么当基础表发生变化时不进行检查。
过去,当基础表发生更改并且生成的 select
的列偏移量错误时,我曾以一种糟糕的方式被它咬伤。请注意,仅通过避免 select *
,此问题 未 得到解决,尽管这通常是一个很好的做法。
此外,如果您有一个定期运行的大型系统(例如,每周或每天),您可能希望放置一个重新编译系统中所有视图的作业。这也确保了他们的执行计划正在更新表的最新统计信息。而且,如果您真的要小心,请使用 SCHEMABINDING
,因此需要有意识地对基础表进行任何更改。