4 index sql-server clustered-index nonclustered-index sql-server-2014
我有一张有 1.45 亿行的表
CREATE TABLE [dbo].[RFTest](
[SnapshotKey] [int] NOT NULL,
[SnapshotDt] [datetime] NOT NULL,
[LoanNum] [int] NOT NULL,
[GLSourceSystem] [varchar](10) NOT NULL,
[FlowDescription] [varchar](30) NULL,
[Account] [varchar](30) NULL,
--- plus 20 more column
)
Run Code Online (Sandbox Code Playgroud)
该表在 SnapshotDt 上分区。
我在我的表上添加了以下索引:
create clustered index ci on RFTest (SnapshotDt, SnapshotKey, LoanNum)
create nonclustered index nci on RFTest (SnapshotDt, SnapshotKey, LoanNum)
include ([GLSourceSystem],[Account],[FlowDescription])
Run Code Online (Sandbox Code Playgroud)
我运行了以下查询:(我使用前 100 名进行测试,因为如果我想运行它,整个表将需要很长时间)
select top 100 *
from RFTest with (index(ci)) -- force index
where LoanNum = 2712
select top 100 *
from RFTest
where LoanNum = 2712
Run Code Online (Sandbox Code Playgroud)
LoanNum列存在于两个索引中,部分键在聚簇中,包括在非聚簇中。
执行计划显示引擎选择非聚集的“nci”索引,而不是聚集的索引。
我想知道为什么。
澄清:
对我来说,在这两种情况下,SQL 都读取了相同数量的数据。并且LoanNum在索引和 BTW 中,LoanNum是键的一部分,所以在我看来,如果它使用聚集索引更有意义。
索引与我发布的完全一样。当我捕获计划时,查询中有一些评论。您在帖子中看到的查询是正确的。我不想保留两个索引,我试图看看哪个表现更好,问题来了。
优化器可以在两种主要策略之间进行选择:
关键是非聚集索引更小,所以扫描它预计会更便宜。这可能看起来违反直觉,因为聚集索引定义具有相同的键,并且非聚集索引包含列,但关键是聚集索引包含存储在行中的所有列- 聚集索引的叶(最低)级别字面上是行内数据。
对于少量预期匹配项,扫描较小索引所节省的成本足以补偿键查找。
顺便说一下,您可能会发现WHERE 1 = 1从查询中删除会导致优化器选择聚集索引扫描。(冗余)常量到常量的比较可防止 SQL Server 参数化查询,因此估计值基于有关LoanNum 2712 的统计信息。如果查询是参数化的,SQL Server 将使用LoanNum值的平均分布,这可能会导致更多的预期行数和计划选择的更改。
也可以看看: