我发现,当一个表同时具有聚簇索引和非聚簇索引(在不同的列上)时,叶级非聚簇页不是指向数据行,而是指向聚簇索引的节点,从那里另一个搜索建立查找数据行。这种额外的间接级别有什么意义?如果聚簇索引有 8 个级别,那么从 NCI 叶页到 CI 根的间接寻址必须遍历这 8 个级别才能到达数据。为什么不把普通的RID存放在NCI的叶子页中,这样我们就可以直接访问数据而不用经过CI的索引结构呢?
我发现,当一个表同时具有聚簇索引和非聚簇索引(在不同的列上)时,叶级非聚簇页不是指向数据行,而是指向聚簇索引的节点,从那里另一个搜索建立查找数据行。这种额外的间接级别有什么意义?如果聚簇索引有 8 个级别,那么从 NCI 叶页到 CI 根的间接寻址必须遍历这 8 个级别才能到达数据。为什么不把普通的RID存放在NCI的叶子页中,这样我们就可以直接访问数据而不用经过CI的索引结构呢?
这样做的原因是您的行的“固定”物理位置 - RID(或行标识符)可能(并且将会!)随着时间的推移而改变 - 想想当需要将行插入到表中时发生的页面拆分页面已经满了。
更新给定表上存在的所有非聚集索引中的那些 RID 很快变得既麻烦又会成为巨大的性能杀手。您的表上可能有 5、10、20 个非聚集索引,SQL Server 必须扫描所有这些索引(基本上扫描整个索引、索引中的所有行,以及 10、20 次)并更新所有 RID。 .. 那是不切实际的 - 很快就会这样。
如果您将聚簇索引的值存储为“行指针”,那么该值通常永远不会改变——而且绝对不需要在每次拆分页面时都更新它。是的,它确实涉及到第二个索引查找操作——键查找——但对于简单的场景,检索单行或几行,这仍然比其他任何事情都高效得多。
简而言之,当聚集索引中的数据发生物理移动(行转发、页面拆分、INSERT 等)时,它涉及更少的 NC 索引条目处理和移动。
大多数情况下,聚集索引条目只需要更改:而不是 NC 索引指针。通过使用 RID,您需要在 NC 索引上做更多的工作。
为了尽量减少查询中的这种查找,您可以使 NC 索引“覆盖”。例如,参见https://stackoverflow.com/questions/1395275/which-is-better-bookmark-key-lookup-or-index-scan/1395322#1395322