使用 NOEXPAND 更新索引视图

Cha*_*ace 5 sql-server t-sql materialized-view update

我先说这是来自 Stack Overflow 上一个未回答问题的交叉帖子
我这样做并不是为了获得对这个问题的更多看法,我希望 DBA 社区分享他们对这是否可能是 SQL Server 中的错误的看法。我认为 SO 社区没有专业知识来决定这一点,所以我在这里重新发布。


假设我有一个 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);
Run Code Online (Sandbox Code Playgroud)

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

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

SELECT Id, txt
FROM V WITH (NOEXPAND);
Run Code Online (Sandbox Code Playgroud)

这很好用。

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

UPDATE V
SET txt = 'Foo';
Run Code Online (Sandbox Code Playgroud)

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

UPDATE V WITH (NOEXPAND)
SET txt = 'Foo';
Run Code Online (Sandbox Code Playgroud)

这会失败,并显示“对象 'V' 上的提示 'noexpand' 无效。”。

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

UPDATE T
SET txt = 'Foo'
FROM T
JOIN V WITH (NOEXPAND) ON V.Id = T.Id;
Run Code Online (Sandbox Code Playgroud)

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

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

我相信有一种称为 rowset-sharing 的优化可能会有所不同,有人知道吗?


更新:

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

NOEXPANDTable HintsIndexed ViewUpdatable Views文档中,没有任何迹象表明不应该工作。该UPDATE语句的文档特别提到某些表提示是不允许的,但仅限于NOLOCK并且READUNCOMMITTED被排除在外。


因此,这甚至可能是 SQL Server 中的一个错误,我应该将其归档到 Azure 反馈中。人们怎么看?

Dav*_*oft 7

这在企业/开发人员版上按您的需要工作:

use tempdb
go

CREATE TABLE dbo.T (id int PRIMARY KEY, b bit NOT NULL, txt varchar(20));
GO
CREATE OR ALTER 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);
GO

UPDATE V
SET txt = 'Foo';
Run Code Online (Sandbox Code Playgroud)

更新有这个计划

在此处输入图片说明

跑步

Microsoft SQL Server 2019 (RTM-CU8) (KB4577194) - 15.0.4073.23 (X64) 
    Sep 23 2020 16:03:08 
    Copyright (C) 2019 Microsoft Corporation
    Developer Edition (64-bit) on Windows 10 Pro 10.0 <X64> (Build 19042: ) (Hypervisor)
Run Code Online (Sandbox Code Playgroud)

您可以在此处添加反馈项以请求在 UPDATE 查询中支持 NOEXPAND。我提交了一个PR来更新文档,以澄清 NOEXPAND 在 UPDATE 中不可用。

  • 这就是为什么它应该是一个增强请求。它被认为是错误的可能性很小。 (2认同)