首页 > 解决方案 > 使用 NOEXPAND 更新索引视图

问题描述

假设我有一个 table T,并且我有一个索引视图V

CREATE TABLE dbo.T (id int PRIMARY KEY, b bit NOT NULL, txt varchar(20));
GO
CREATE VIEW dbo.V
WITH SCHEMABINDING AS
  SELECT T.Id, T.txt
  FROM dbo.T AS T
  WHERE T.b = 1;
GO
CREATE UNIQUE CLUSTERED INDEX idx_V ON dbo.V (Id);

在这个简单的例子中,它基本上只是一个过滤索引,但它也可以有连接等。

我现在想在Twhere中选择一些行,这里b = 1的过滤视图非常有用,而且我在 Standard 所以必须使用NOEXPAND(或者它对于视图匹配来说太复杂了):

SELECT Id, txt
FROM V WITH (NOEXPAND);

现在我想将这些行更新为某个值。该视图符合可更新的条件,因此我可以这样做:

UPDATE V
SET txt = 'Foo';

这不使用索引视图来查找要更新的行,即使它需要它们来实际更新视图。我想做的是像普通表索引一样使用视图,并确定要从中更新的行,将它们传递给 Clustered Index Update on T,然后是视图上的 Update。所以我试试这个:

UPDATE V WITH (NOEXPAND)
SET txt = 'Foo';

这失败了"Hint 'noexpand' on object 'V' is invalid."

我知道我可以通过这样的查询来解决它:

UPDATE T
SET txt = 'Foo'
FROM T
JOIN V WITH (NOEXPAND) ON V.Id = T.Id;

但这意味着额外的 Seek。不仅如此,它还在随后的索引视图更新中添加了一个过滤器,以检查行是否与视图匹配(连接视图需要评估连接),显然,它们必须与视图匹配。

有没有办法让它以我想要的方式工作?


更新:

将视图放在FROM子句中,甚至放在派生表、CTE 或其他视图中都无济于事。一旦它查看解析器它正在用于更新,它就会失败。

在Table HintsIndexed ViewUpdatable Views文档中没有任何指示不NOEXPAND应该工作。该声明的文档特别提到某些表格提示是不允许的,但只是被排除在外(最近更新为添加但没有解释)UPDATENOLOCKREADUNCOMMITTEDNOEXPAND

标签: sqlsql-servertsqlindexed-view

解决方案


推荐阅读