快速回答,是的,删除主键(此外,用单个标识列替换当前的多列主键)然后在 Month_ID 上创建 NCI 会更好/更快/更有效。
聚集索引- 它是数据。它包含表中每一行的每一列。CI 只能有一个,因为表数据只需要存在一次。每行都有一个键...
主键- 它是在聚集索引中识别行的键。
非聚集索引- 它充当聚集索引中行的列子集的表。
保持简单,非聚集索引包含的数据比聚集索引少,并且它以某种方式对数据进行排序(Month_id ASC),这使得对它的查询比对 CI 的查询更有效(A、B、C、Month_ID )。SQL Server 无法“深入”CI 主键或行数据并说,“嘿,我正在按 Month_ID 进行过滤,所以我将直接进入该列。” 根据聚集索引的性质,SQL Server 会“读取”所有 CI 行(索引扫描)、每一列、每一个数据字节。非常低效和浪费,因为您的 WHERE 子句将过滤掉很多这些行。
非聚集索引仅包含列的子集,因此它更有效,因为它可以说:“嘿,我正在按 Month_ID 过滤,我只包含 Month_ID,aannnd Month_ID 是升序的,所以我可以直接跳到我想要的行!” (索引搜索)。效率更高,因为 SQL Server 只会“读取”您想要返回的行。
更高级一点,因为非聚集索引只有 Month_ID,但您正在查询聚集索引中的所有列,SQL Server 需要能够从 NCI 返回 CI 以获取其余列。为此,CI 的主键与列子集一起存储在 NCI 中。所以NCI实际上就像一个(Month_ID,CI主键)的两列表。
如果您的主键很可怕,那么您的 NCI 也将很糟糕,因此效率会降低(更多的磁盘读取、更多的缓冲池消耗、坏的数据库内容)。
免责声明:在某些特定情况下,您希望每列都成为聚集索引键/pk。我不觉得这适用于这里,但这是可能的。如果您有一个频繁使用的查询,它在 where 子句或连接中引用表的每一列,那么覆盖聚集索引可能是有益的。