为什么查询优化器不使用负过滤索引

Min*_*ing 0 sql-server-2008 sql-server optimization query-performance

我有一张具有以下结构的表,如您所见,有一个聚集索引和两个非聚集索引,一个非聚集索引是 IX_ParentId_Include,另一个是 FLIX_ParentId_Include

除了第二个索引被过滤之外,它们是相同的。

CREATE TABLE [dbo].[PhotoRepo] (
    [PhotoRepoId]              INT            IDENTITY (1, 1) NOT FOR REPLICATION NOT NULL,
    [TypeId]                   TINYINT        NULL,
    [ParentId]                 INT            NULL,
    [RemoteLocation]           VARCHAR (4000) NOT NULL,
    [UploadedAt]               DATETIME       NOT NULL,
    [UploadedBy]               VARCHAR (255)  NULL,
    [FileSize]                 INT            NOT NULL,
    [DefaultChild]             BIT            NOT NULL,
    [RemoteLocationUploadedAt] DATETIME       NULL,
    CONSTRAINT [PK_FileList] PRIMARY KEY NONCLUSTERED ([PhotoRepoId] ASC)
);


GO
CREATE CLUSTERED INDEX [IX_PhotoRepoId]
    ON [dbo].[PhotoRepo]([PhotoRepoId] ASC);


GO


CREATE NONCLUSTERED INDEX [IX_ParentId_Include]
    ON [dbo].[PhotoRepo]([ParentId] ASC)
    INCLUDE([RemoteLocation], [DefaultChild], [TypeId]);
GO

CREATE NONCLUSTERED INDEX [FLIX_ParentId_Include]
    ON [dbo].[PhotoRepo]([ParentId] ASC)
    INCLUDE([RemoteLocation], [DefaultChild], [TypeId])
    WHERE TypeId <> 7;

GO
Run Code Online (Sandbox Code Playgroud)

现在,当我在启用执行计划的情况下运行此查询时,查询优化器不使用过滤器索引,我希望它应该更有效,它使用 IX_ParentId_Include。仅当我强制它或删除 IX_ParentId_Include 时,它​​才使用过滤器索引

有谁知道为什么?

SELECT 
    *
FROM   PhotoRepo
WHERE  
    typeid <> 7 and
    parentid = 123
Run Code Online (Sandbox Code Playgroud)

PS:有 30% 的行 typeid = 7

Aar*_*and 6

为什么你认为它应该使用过滤索引?您已SELECT *在查询中使用,并且您的谓词不仅仅涉及过滤条件。SQL Server 将不得不在覆盖它的另一个索引中查找这些列(您的SELECT *计划应该包括一个键查找来检索这些其他列)。

SQL Server 将根据统计信息/基数(例如,当前有多少行与过滤器匹配,总共有多少行)来决定它应该使用哪个索引。在这种情况下,它可能是抛硬币,因为它可以查找与ParentId谓词匹配的 19 行,并且这样做不会花费更多的 I/O。如果它代表表中比 30% 小得多的部分,它可能会选择过滤索引。但是,如果您添加OPTION (RECOMPILE)到查询中,您应该会看到它的作用。根据您的参数化设置,它可能正在使用以不同参数值(例如,与索引过滤器不匹配的参数值)缓存的计划。

在这种情况下,我相信您会看到这种行为,因为 RTM。请安装Service Pack 3并考虑累积更新 16。我快速浏览并没有看到任何与过滤索引相关的内容,但这可能是其他一些优化器不稳定的副产品,同时已修复。无论如何,我实在想不出有什么好的理由让您此时继续运行 RTM。

也可能与这些其他“已知功能缺陷的错误”有关:

我还写了一篇关于过滤索引的一系列限制的博客,并指出了大量相关的 Connect 项目。其中大部分仍未修复,并且在大多数情况下,过滤索引自首次引入以来就完全没有受到关注。如果您打算使用这些对象,并希望使用它们来加速您的查询,那么您最好熟悉所有这些限制,并考虑使用索引提示来强制在某些情况下使用它们。场景。使用索引提示的注意事项,当然:

  1. 它可能不会更好地工作(您并不总是比优化器更了解);它可能对某些查询效果更好,但不是全部。如果 (a)可以,并且 (b) 它认为它是最有效的访问方法,则 SQL Server 通常会使用过滤索引。
  2. 如果索引被删除或使用新名称重新创建,查询将失败。