CREATE INDEX [IX_Foo] ON [Foo] ( Id ASC ) INCLUDE ( SubId )
在这种特殊情况下,我遇到的性能问题(对Id和SubId都是缓慢的SELECT过滤)可以通过简单地将SubId列移动到索引中而不是包含列来修复.
这让我想到,我不明白背后的推理包括列,一般来说,它们只能是索引本身的一部分.即使我不特别关心索引中的项目本身,在索引中列出列表,而不仅仅是被包含在内.
经过一些研究,我知道对索引列(最大的索引宽度,以及一些无法索引的列类型,如“image”)可以进行一些限制.在这些情况下,我可以看到您将被迫将列添加到索引页数据中.
我唯一可以想到的是,如果在SubId上有更新,如果列被包括(尽管索引中的值需要更改),该行将不需要被重新定位.还有什么我失踪的吗?
我正在考虑通过数据库中的其他索引,并尽可能地在索引中包括列.这会是一个错误吗?
我主要对MS sql Server感兴趣,但也欢迎有关其他DB引擎的信息.
解决方法
在你的情况下,你有一个表Foo和一些字段,包括一个Id(我认为是主键)和一个SubId,这是一些额外的ID.
你也有一个索引IX_Foo,我假设现在只有Id.
所以现在你需要找到IdId 4的SubId.
SELECT Id,SubId FROM Foo WHERE Id=4
> sql Server将查看SELECT语句并确定它可以使用IX_Foo
>然后,您将在索引IX_Foo中搜索值Id = 4
>当它找到它时,它现在也需要SubId的值
>非聚集索引IX_Foo将包含聚类键值
>使用该集群密钥值,sql Server将执行“书签查找”以查找整个数据行所在的实际数据页面
>它将获取该页面并从中提取SubId的值
>它将返回这些值以满足您的查询
这里的要点是:一旦sql Server在IX_Foo索引中找到您的Id = 4,那么它将需要执行另一个I / O操作(书签查找)来获取整个数据行,以便能够找到SubId值.
如果您有覆盖索引,例如IX_Foo还包括SubId,消除了额外的I / O来进行书签查找.在IX_Foo索引中找到值Id = 4之后,非聚集索引中的索引页面也将包含SubId的值 – sql Server现在可以在SELECT查询中返回您要求的两个值,而无需执行额外的(潜在的昂贵和因此缓慢)书签查找只是为了获取另一个Id列.
这是覆盖索引的主要优点 – 如果您只需要一个或两个额外的列,除了您正在进行查找的索引值之外,通过将这些值包含在索引本身中,您可以自行保存很多书签查找,因此快速的事情显着.但是,您应该只包含很少的信息,而不是将整个数据行重复到所有非聚集索引中!这不是重点.
更新:权衡是这样的:如果您有一个索引(Id,SubId),索引中的所有页面都有两列 – 整个索引树.
如果您使用INCLUDE(SubId),SubId字段仅存在于叶级别.
意即