同一列上的非聚集索引和聚集索引

4

我在Stackoverflow上看到了这篇帖子。第一个回答中提到聚簇索引包含表中所有的数据,而非聚簇索引仅包含列和聚簇索引或堆(没有聚簇索引的表)上的行的位置。非聚簇索引如何包含聚簇索引的位置?它只包含按节点排序的列值,并且每个节点指向具有该节点值的行,对吗?


如果在列a上定义了非聚集索引,并且在列b上定义了聚集索引,那么将会有两个独立的结构。聚集索引将按照列b中的值的顺序对行进行排序,然后非聚集索引将使用指向数据的B树来排列列a中的值(按照列b中的值的顺序进行排序)。非聚集索引如何适应另一列b - SexyBeast
在这种情况下,非聚集索引将在其叶级页中包含“b”(聚集键)的值。如果在非聚集索引中找到了“a”的值,但是查询需要更多数据(例如SELECT *......),则使用“b”值来进行键查找,以便在聚集索引中查找实际的数据页并返回查询的值。 - marc_s
2个回答

4
假设您谈论的是SQL Server,并且假设您的表上有一个聚集索引(正如您应该有的那样)。
然后,非聚集索引具有您在CREATE INDEX语句中定义的列,以及它具有组成聚集索引的列(如果存在)。
该聚集键值是指向实际数据所在位置的“指针”。
如果查询执行器通过非聚集索引寻找某个值并找到匹配项,则
  • 如果您只关心该值-那么您只需返回该值。

  • 或者非聚集索引可能还具有一些包含的列(在叶级别页面中),并且通过这些列,可以满足查询(请求的所有列都存在),因此您将获得所请求的值。

  • 或者您想要的值不全部在非聚集索引叶级别页面中(如果您一直使用SELECT *,那就尤其如此),然后查询执行程序必须从非聚集索引中获取聚集键值,并返回到聚集索引,执行所谓的键查找,通过聚集索引进行搜索,并找到关联的数据页,其中存储了完整的行->现在,查询执行程序可以返回您所请求的值。

有一个非常好的解释,请参见这篇博客文章。它说:

在非聚集索引中:
....
2.b. 如果表具有聚集索引,或者索引位于索引视图上,则行定位器是该行的聚集索引键。 SQL Server通过使用存储在非聚集索引的叶子行中的聚集索引键,在聚集索引中搜索以检索数据行。

或者查看关于SQL Server索引的整个系列中的这篇博客文章, 它还解释了存储在非聚集索引叶级页面中的“书签”。


我不明白,非聚集索引本身就持有指向完整数据行的指针,为什么还需要聚集索引呢? - SexyBeast
@Cupidvogel:非聚集索引的叶级页面具有自己的索引列、任何包含的列和聚集键的值,但那不是实际的数据页位置。一旦找到了NC叶级页面并且需要完整的数据页,就需要进行键查找(在聚集索引中进行索引搜索)以获取实际的数据页。 - marc_s
在叶级别可以直接指向数据的情况下,通过添加聚集索引形式的另一层间接性有何意义? - SexyBeast
@Cupidvogel:您不必不断更新集群索引键值 - 尽管您可能必须对“直接”页面标识符进行此操作,如果例如发生页面拆分(并且该操作可能非常昂贵!)。想象一下,您有一个具有10个、15个非聚集索引的表 - 现在发生了页面拆分。ALL 指向该页面的非聚集索引现在都必须进行更新 - 开销极大! - marc_s
1
@Cupidvogel:是的,但页面分割不会改变聚集键值! - marc_s
显示剩余3条评论

3

很容易就能想象成这样:

假设你有一张客户表,例如customer(id、name、age、adress)。在这个表上,你有一个按年龄排序的聚集索引。这意味着你的数据在硬盘上是按年龄排序的。当你想进行范围查询时,这非常有利,比如:

SELECT * FROM customer WHERE age > 18;

然后,只需进行几个顺序读取操作,就可以从硬盘中获取数据。如果索引未聚集,则每个匹配的客户元组都需要进行一次磁盘访问(包括数据的查找)。
也许对于您的应用程序,您还需要通过id访问用户。这意味着如果没有id的附加索引,由于它按年龄排序并且没有索引,您将不得不浏览整个文件才能找到特定的id!为了避免这种情况,您可以创建第二个id索引。现在,您可以在此索引中搜索id,并且索引的叶子节点,其中包含您正在查找的客户,指向您在硬盘上找到元组的位置(通过年龄聚类)。因此,您不必读取整个表,需要更少的磁盘访问(通常是2次索引查找+1次元组提取)。
编辑: 我没有看到您谈论同一列的事情。我可以想象的一件事是,出于上述原因,在一列上做一个聚集索引,然后在此和另一列上创建一个组合索引。例如,这可以用于进行仅索引查找,其中索引中具有所有所需属性,根本不需要进行页面提取。另一个原因是为范围查询使用聚集B+-Index和为等式查询使用Hash-Index。但我认为这里的好处微乎其微。
希望这有所帮助!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接