SELECT 使用非 PK 索引而不是 PK

Tip*_*ipx 5 index execution-plan sql-server-2012

[dbo].[Programs]表中,列[Id]是主键(不是复合键的 par)。该表上还有很多其他索引。

当我运行这个简单的查询时,SELECT [Id] FROM [dbo].[Programs]执行计划如下:

执行计划

我的问题是:为什么不只是使用 PK 索引?

性能不是问题,因为该表有 23 行,但我只是觉得它很奇怪,我想了解为什么 SqlServer 是正确的,以及为什么我认为它会更好是错误的。

Aar*_*and 10

它与主键无关,只是主键通常是集群的。

在您的情况下,SQL Server 不使用聚集索引,因为根据定义,聚集索引包括表中的所有列。由于您只想要Id,它正在使用满足您的查询的更薄的索引,因为这样做的工作较少,即使您的表只有一列,它仍然会选择非聚集索引。

如果我让你从冰箱里给我拿一瓶啤酒,你的选择是:

  1. 轮过整个冰箱
  2. 移交案件
  3. 带来一瓶啤酒

在您的情况下,1. 使用聚集索引,2. 使用一些宽索引,3. 使用仅包含Id.

聚集索引并不总是操作的最佳选择,就像法拉利不是您一直想要用于执行任务的汽车(例如,与某人比赛与拖曳游艇)。


RDF*_*ozz 8

查询优化器将查看获取数据的最快方式(据其所知)。

检查相同查询的执行计划可能会很有趣,ORDER BY [Id]添加。

我假设它Id不仅是主键,而且它的索引是表上的聚集索引。这意味着,要遍历索引并挑选出Id值,它必须读取整个表(因为聚集索引实际上是按索引键排序的完整表)。

我还将假设IX_SupplyProgramId包含的其他列数量有限。请注意,所有索引都将具有聚集索引的值,因为这就是它们将索引连接回实际行的方式。并且,Id将包含的每个值

因此,如果读取聚集索引必须读取的数据量可能大于在其他索引中读取的数据量。读取是查询引擎执行的最昂贵的操作之一,因此减少读取是一件好事。

因此,它使用较小的索引Id而不是聚集索引来获取值。

  • @Tipx 我不相信这种独特性与这种情况有任何关系。 (2认同)
  • @Tipx - Aaron 是正确的 - 即使有 20-30 行,每个唯一的 `SupplyProgramId` 值,每一行都必须出现在索引中。由于每一行都出现在索引中,因此每个 `Id` 出现在索引中。并且,请注意“Id”是唯一的(作为主键)——“SupplyProgramId”的重复并不意味着“Id”的重复。 (2认同)