如何通过视图获取 SEEK 访问转换后的 ID

jer*_*ech 5 performance sql-server execution-plan view type-conversion query-performance

假设我有一张桌子:

-- just for test purposes
CREATE TABLE SomeTable (
    ID INT IDENTITY(1,1) NOT NULL CONSTRAINT PK__SomeTable__ID PRIMARY KEY CLUSTERED
    ,SomeColumn1 NVARCHAR(50) NULL
    ,SomeColumn2 DATETIME NULL
    );

-- populate table with some rows
INSERT INTO SomeTable DEFAULT VALUES;
GO 1000
Run Code Online (Sandbox Code Playgroud)

因为第三方应用程序有一个视图将表的 ID 列从INTNVARCHAR(假设它是必须的):

CREATE VIEW ThirdPartyView AS
SELECT
    ID = CAST(ID as NVARCHAR(10))
    ,C1 = SomeColumn1
    ,C2 = SomeColumn2
FROM SomeTable;
Run Code Online (Sandbox Code Playgroud)

然后当我通过 ID 访问一行时,我得到一个 INDEX SCAN:

SELECT *
FROM ThirdPartyView
WHERE ID = N'1'
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

我明白为什么。

我该怎么做才能在查询之外获得 INDEX SEEK?

社论/情况:

  • 基表 (SomeTable) 定义无法更改(无法添加列)
  • 视图必须具有相同的列(不能添加列)
  • 可以定义任何索引
  • 我可以将视图设为索引视图,但更愿意避免使用该选项
  • 对方期望 ID 列的数据类型是NVARCHAR. 不幸的是,我必须满足这个条件。或者我被告知要见他们。如果不是,他们的应用程序可能会失败。

Mar*_*ith 9

问题是您通过视图进行的查询与执行相同

SELECT *
FROM SomeTable
WHERE CAST(SomeTable.ID as NVARCHAR(10)) = N'1'
Run Code Online (Sandbox Code Playgroud)

CAST谓词中的几乎任何一列都会使该谓词不可判断。我所知道的唯一的例外是一个CASTdatetimedateVARCHARNVARCHAR下一些归类。

NVARCHARto没有这样的例外INT

你可能希望它会做类似的事情

WHERE SomeTable.ID = TRY_CAST('Your search string' as int)
Run Code Online (Sandbox Code Playgroud)

但事情并没有那么简单。如果您的搜索字符串是'1'两个将返回相同的结果,但对于搜索字符串'¹'(上标 1),转换int失败但字符串比较在某些排序规则下比较相等。相反,对于搜索字符串' 1'(带有前导空格),转换int和比较将丢弃前导空格并比较相等,但字符串比较将比较不相等(与0转换为时转换为的空字符串类似int

可能的解决方案

通常,您可以在引用计算列的基表上创建索引视图或新索引,但与CAST从视图中删除以便可以查找现有索引相比,两者似乎都不太理想。

计算列

您可以SomeTable使用定义创建一个计算列CAST(ID as NVARCHAR(10)),然后对其进行索引。

ALTER TABLE SomeTable ADD strID AS CAST(ID as NVARCHAR(10));    

CREATE INDEX IX ON SomeTable (strID ) INCLUDE (ID, SomeColumn1, SomeColumn2);

SELECT *
FROM ThirdPartyView
WHERE ID = N'1';
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

索引视图

鉴于问题中的限制,计算列的想法似乎被排除在外。另一种方法是创建索引视图,但您可能需要更改查询文本才能使其正常工作。

  • 在除企业版之外的所有版本中,都NOEXPAND需要提示来获取要匹配的索引视图。
  • 如果您使用的企业版,则无论您对原始视图进行索引还是创建副本,原则上自动匹配都可以工作...
  • ...但索引视图匹配只会在优化的后期阶段考虑。如果查询足够便宜,优化将在到达该点之前结束。特别是在您的情况下,您还需要与琐碎的计划作斗争。我向表中添加了 100 万行数据,但索引视图仍未命中 - 因为该计划低于并行性的成本阈值,并且没有继续进行除微不足道之外的进一步优化阶段。