我最近在我维护的数据库中遇到了一个索引:
CREATE INDEX [IX_Foo] ON [Foo]
( Id ASC )
INCLUDE
( SubId )
在这种特殊情况下,我遇到的性能问题(Id和SubId上的慢速SELECT过滤)可以通过简单地将SubId列移动到索引中而不是作为包含列来修复。
这让我想到了我根本不理解包含列的原因,一般来说,它们可能只是索引本身的一部分。即使我不特别关心索引本身的项目,在索引中使用列而不是简单地包含列也有任何缺点。
经过一些研究后,我发现对索引列中的内容有很多限制(索引的最大宽度,以及一些不能像'image'那样索引的列类型)。在这些情况下,我可以看到您将被迫在索引页数据中包含该列。
我唯一能想到的是,如果SubId上有更新,如果包含该列,则不需要重新定位该行(尽管索引中的值需要更改)。还有其他我缺少的东西吗?
我正在考虑浏览数据库中的其他索引,并尽可能地在索引中包含列。这会是一个错误吗?
我主要对MS SQL Server感兴趣,但也欢迎其他数据库引擎的信息。
答案 0 :(得分:8)
到目前为止,答案都是正确的 - 但是它们可能无法传达你从覆盖指数中获得的足够的答案。
在您的情况下,您有一个表Foo
和一些字段,包括Id
(我假设是主键)和SubId
,这是一个额外的ID某种。
你还有一个索引IX_Foo
我认为它现在只有Id
。
现在您需要找到SubId
的{{1}}。
Id=4
SELECT Id, SubId
FROM Foo
WHERE Id=4
IX_Foo
Id=4
IX_Foo
的值SubId
将包含聚类键值IX_Foo
的值这里的要点是:一旦SQL Server在SubId
索引中找到了Id=4
,它就需要进行另一个I / O操作,书签查找,以获取整个数据行,以便能够找到IX_Foo
值。
如果您有覆盖索引,例如SubId
还包括IX_Foo
,用于执行书签查找的额外I / O被删除。在SubId
索引中找到值Id=4
后,非聚集索引中的索引页面也将包含IX_Foo
的值 - SQL Server现在可以返回您提出的那两个值在您的SELECT查询没有必须执行额外(可能很昂贵,因此很慢)书签查找只是为了获取另一个Id列。
这是覆盖索引的主要好处 - 如果你只需要一个或两个额外的列,除了你正在进行查找的索引值,通过将这些值包含在索引本身中,你可以节省很多书签查找,从而显着加快速度。但是,您应该只包含极少数和少量信息 - 不要将整个数据行复制到所有非聚集索引中!这不是重点。
UPDATE:权衡是这样的:如果你有一个索引(Id,SubId),索引中的所有页面都有两列 - 整个索引树通过。
如果包含INCIUDE(SubId),则SubId字段仅出现在叶级别。
这意味着
答案 1 :(得分:7)
在索引中有一个附加列的原因是,当您执行只需要索引使用的列的查询时,您可以自己完成索引中的查询。这样可以节省一些时间和资源返回到表中。发生这种情况时,我们说索引是查询的覆盖索引。
您可能不希望将此附加列作为“索引正确”的一部分的原因是因为当您对该列执行插入或更新时,您更可能需要对索引的某些部分进行重新排序。
答案 2 :(得分:3)
在索引中使用include允许将索引用作覆盖索引(即,可以单独使用该索引来满足某些查询,而无需对聚簇索引执行书签查找),而无需将这些列添加到实际树的一部分索引,从而保持索引的大小。 (包含的列仅添加到索引的叶节点中。)