尝试强制使用过滤索引时出现问题
-
28-09-2020 - |
题
昨天我试图对过滤索引进行一些测试,并创建了一个相当简单的情况:
CREATE TABLE IndexTest
(
ID INT NOT NULL IDENTITY(1,1) CONSTRAINT pk_IndexTest PRIMARY KEY,
Col1 CHAR(1)
)
GO
CREATE INDEX ix_IndexTest ON IndexTest(Col1)
WHERE Col1 IS NOT NULL
GO
INSERT INTO IndexTest VALUES ('A'),('B'),('C'),('D')
INSERT INTO IndexTest VALUES (''),(''),(''),('')
INSERT INTO IndexTest VALUES (NULL),(NULL),(NULL),(NULL)
GO
然后,我尝试使用提示运行以下查询,以强制它使用过滤索引。
SELECT *
FROM IndexTest WITH (INDEX(ix_IndexTest))
GO
但我不断收到错误:
由于此查询中定义的提示,查询处理器无法生成查询计划。重新提交查询,不指定任何提示,也不使用 SET FORCEPLAN。
如果我移除过滤器但不连同它,它会起作用。我什至尝试以各种方式更改过滤器,例如 WHERE Col1 = ''
ETC。每当我有过滤器时,我都会收到该错误。谁能告诉我为什么?难道我做错了什么?
我在 SQL Server 2012 和 2014 实例上尝试了此操作,并在此处创建了它的 sqlfiddle:
http://www.sqlfiddle.com/#!6/4a850/1
编辑: 不确定这是否重要,但具体而言,我想看看是否可以看到索引实际包含哪些行。这个想法来自于看到有人使用这种技术从损坏的表中恢复数据(使用未过滤的索引)。
解决方案
可能的脱节是过滤索引不会自动为您过滤结果 - 您必须编写一个与索引的过滤谓词匹配的 WHERE 子句才能使用该索引。
换句话说,如果您只想获取行 WHERE Col1 IS NOT NULL
, ,你还需要一个 WHERE
子句来限制行。如果 SQL Server 无法使用您试图强制满足查询返回的所有行的索引,则通过定义包含比表更少(或相同*)行的索引来做到这一点,它无法运行。
*
可能有些情况我还没有测试过,这是否可行;例如,如果该列被限制为NOT NULL
(或者所有行恰好与过滤谓词匹配),那么过滤索引将通过扩展表示整个表中的行。但这是一个非常人为且不切实际的场景(即使它有效)。SQL Server 无法针对所有行当前恰好与过滤器匹配的情况生成计划,因为单个插入或更新可能会破坏它。
如果您尝试从非聚集索引中查找数据,因为基础表/CI 已损坏,那么您可能会有更好的运气 DBCC IND/PAGE
或者模仿使用十六进制编辑器的 Paul Randal。