You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SQL Server为何能在非聚集索引查找中使用聚集索引列作为查找谓词?

聚集索引键列在非聚集索引查找中作为谓词的行为解释

我发现了一个奇怪的现象,希望有人能提供相关文档或解释其实现原理:
我有一张包含Key1、UnexpectedClusteredKey、NonClusteredKey列的表,创建了聚集索引PK_Index(Key1, UnexpectedClusteredKey)和非聚集索引IX_Index(Key1, NonClusteredKey)。当执行包含所有三列过滤条件的SELECT查询时,实际执行计划显示使用了非聚集索引,且查找谓词包含全部三列。
我原本预期会使用聚集索引并通过残留谓词过滤NonClusteredKey,或是使用非聚集索引并通过残留谓词过滤UnexpectedClusteredKey(我明白无需键查找,因为两个索引都是覆盖索引)。这种能同时利用三列作为查找谓词的行为对我来说是新特性,我猜测这是因为UnexpectedClusteredKey是聚集索引中未包含在非聚集索引里的列,但找不到相关行为的官方说明。

测试代码

DROP TABLE test.tbl_IndexSeekTest
CREATE TABLE test.tbl_IndexSeekTest
( 
    Key1 INT, 
    UnexpectedClusteredKey INT,
    NonClusteredKey INT
)
CREATE CLUSTERED INDEX PK_Index on test.tbl_IndexSeekTest
(
    Key1,
    UnexpectedClusteredKey
)

CREATE NONCLUSTERED INDEX IX_Index on test.tbl_IndexSeekTest
(
    Key1,
    NonClusteredKey
)

INSERT INTO test.tbl_IndexSeekTest VALUES (1,1,1),(1,2,1),(1,3,1),(1,4,1),(1,5,1)

SELECT * FROM test.tbl_IndexSeekTest
WHERE Key1 = 1
AND NonClusteredKey = 1
AND UnexpectedClusteredKey = 1

原理解释

这是因为非聚集索引的叶节点会自动包含聚集索引的全部键列(即Key1和UnexpectedClusteredKey),作为行定位器来指向对应的聚集索引行。所以你的非聚集索引IX_Index实际的结构是:

  • 显式索引键:Key1、NonClusteredKey
  • 隐式包含列:UnexpectedClusteredKey(聚集索引键)

当SQL Server生成执行计划时,查询优化器可以利用非聚集索引中所有可用的列构建查找谓词——因为UnexpectedClusteredKey已经存在于非聚集索引的叶节点中,不需要额外的键查找操作。优化器会评估两种索引的使用成本:

  • 使用聚集索引PK_Index时,需要先通过Key1+UnexpectedClusteredKey定位行,再通过残留谓词过滤NonClusteredKey
  • 使用非聚集索引IX_Index时,可以直接用Key1+NonClusteredKey+UnexpectedClusteredKey作为查找谓词,精准定位符合所有条件的行,避免残留过滤,执行成本更低

这种行为是SQL Server索引的标准特性,官方文档明确说明:非聚集索引的叶级行包含完整的聚集键,用于唯一标识对应的行。查询优化器会自动识别这些隐式包含的聚集键列,并将其纳入谓词评估,以生成更高效的执行计划。

内容的提问来源于Stack Exchange,提问作者Fernando Rojo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 18:23:22