关于sql server:同一列上的非聚集索引和聚簇索引

Non-clustered index and clustered index on the same column

我在StackOverflow看到了这篇文章。第一个答案提到了类似聚集索引拥有表的所有数据,而非聚集索引只有列+聚集索引的位置或行(如果它在堆上)(没有聚集索引的表)。非聚集索引如何具有聚集索引的位置?它只包含排序为b-treee中节点的列值,每个节点都指向列具有该节点值的行,对吗?


假设您在谈论SQL Server,并且假设您的表上有一个聚集索引(如您应该的那样)。

然后,非聚集索引包含您在CREATE INDEX语句中定义的列,再加上它包含构成聚集索引(如果存在)的列。

集群键值是指向实际数据所在位置的"指针"。

如果查询执行器通过非聚集索引查找值并找到匹配项,则

  • 要么你只关心这个价值,要么你就拿回这个价值。

  • 或者,非聚集索引也可能有一些包含的列(在叶级页中),使用这些列,可以满足查询(请求的所有列都存在),因此可以返回请求的值。

  • 或者,您需要的值并不都在非聚集索引叶级页面中(如果您一直执行SELECT *),那么查询执行器必须从非聚集索引中获取聚集键值,然后返回聚集索引,执行所谓的键查找,搜索聚集索引,并查找存储完整行的关联数据页->现在查询执行器可以返回您请求的值

为了一个很好的解释-看这里的博客帖子。上面写着:

In NonClustered Index:
....
2.b. If the table has a Clustered index, or the index is on an Indexed view, the row locator is the Clustered index Key for the row. SQL
Server retrieves the data row by searching the Clustered index using
the Clustered index Key stored in the Leaf row of the NonClustered
index.

或者在一个关于SQL Server索引的完整系列中看到这个博客文章,它也解释了存储在非聚集索引叶级页面中的"书签"。


很容易想象这样:

您有一个客户表,例如客户(ID、名称、年龄、地址)。在这个表中,您有一个关于年龄的聚集索引。这意味着您的数据在硬盘上按时间排序。当您想进行如下范围查询时,这非常有用:

1
SELECT * FROM customer WHERE age > 18;

然后,只需几次连续读取就可以从硬盘中提取数据。如果索引未分类,则必须对每个匹配的客户元组进行一次磁盘访问(包括数据查找)。

也许对于您的应用程序,您还需要通过ID访问用户。这意味着,如果没有ID上的附加索引,您将不得不运行整个文件来查找特定的ID,因为它是按年龄排序的,而您没有索引!为了避免这种情况,您可以在ID上创建第二个索引。现在,您可以在该索引中搜索一个ID,并在包含您要查找的客户的索引叶中,指向磁盘上(按年龄分组)数据中找到元组的位置。通过这种方式,您不必读取整个表,只需很少的磁盘访问(一般情况下,索引查找需要2个磁盘访问,获取元组需要1个磁盘访问)。

编辑:我没看到你在谈论同一个专栏。我能想象的一件事是,由于上面描述的原因,您对一列执行一个聚集索引,例如,对该列和另一列的另一个组合索引。这对于只进行索引查找很有用,这里索引中有所有必需的属性,根本不需要进行页面提取。另一个原因是范围查询有一个聚集的B+索引,等式查询有一个散列索引。但我认为这里的好处是微不足道的。

希望这有帮助!