使用 NOEXPAND 更新索引视图

问题描述 投票:0回答:1

假设我有一张桌子

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);

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

我现在想在

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

SELECT Id, txt
FROM V WITH (NOEXPAND);

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

UPDATE V
SET txt = 'Foo';

这不使用索引视图来查找要更新的行,即使它需要它们来实际更新视图。我希望它做的是像普通表索引一样使用视图,并识别要从中更新的行,将它们传递给

T
上的聚集索引更新,然后对视图进行更新。所以我尝试这个:

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;

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

有什么方法可以让它按照我想要的方式工作吗?


更新:

将视图放在

FROM
子句中,甚至放在派生表、CTE 或其他视图中都没有帮助。一旦解析器发现它正在用于更新,它就会失败。

没有迹象表明

NOEXPAND
Table HintsIndexed ViewUpdatable Views 文档中不起作用。
UPDATE
声明
的文档特别提到不允许某些表提示,但仅排除
NOLOCK
READUNCOMMITTED
(最近更新添加
NOEXPAND
但没有解释)

sql sql-server t-sql indexed-view
1个回答
0
投票

你想要的都是废话。更新始终发生在表中,并根据视图定义随后应用于视图。

这是准确的执行顺序。

您是说您想先更新视图,然后更新表。即使你认为你已经说过了,这就是你在现实中所说的。

因此,无论您希望如何“识别”行,UPDATE语句都会首先进入表,识别表中的行并更改所需的值,然后它会对视图本身进行相同的更新,基于视图的实际定义。

请记住:先是表,然后是视图,而不是相反。这不仅适用于 SQL Server,也适用于提供与索引视图类似功能的所有其他关系数据库引擎。

© www.soinside.com 2019 - 2024. All rights reserved.