非群集(非PK)索引是否需要包含群集(PK)列?

时间:2018-06-15 02:39:41

标签: sql sql-server indexing

例如,这里有FOO表上的2个索引:

ALTER TABLE [dbo].[FOO] 
    ADD CONSTRAINT [PK_FOO] PRIMARY KEY CLUSTERED ([id] ASC)

CREATE NONCLUSTERED INDEX [IX_FOO] 
    ON [dbo].[FOO] ([id] ASC, [a] ASC, [b] ASC)

使用IX_FOO列进行过滤时,许多查询都在使用aid中的IX_FOO列似乎是多余的,因为PK_FOO正在索引它。因此,我想要从id中删除IX_FOO列,如下所示:

CREATE NONCLUSTERED INDEX [IX_FOO2] 
    ON [dbo].[FOO] ([a] ASC, [b] ASC) 
    INCLUDE ([id])

但我不确定自己。索引是否需要包含PK列?

2 个答案:

答案 0 :(得分:2)

不,不。非聚簇索引将指向主表的主键,因此无需将其(主键)添加到任何非聚簇索引。

换句话说,所有非聚簇索引都隐式包含表的聚簇索引。

答案 1 :(得分:2)

索引中列的顺序很重要。

(ID, a, b)上的索引与(a, b) include (id)上的索引非常不同。

搜索时可以使用(ID, a, b)上的第一个索引:

  1. ID,a,b:WHERE ID = 1 AND a = 2 AND b = 3
  2. ID,a,范围b:WHERE ID = 1 AND a = 2 AND b > 3 AND b < 5
  3. ID,a:WHERE ID = 1 AND a = 2
  4. ID,范围:WHERE ID = 1 AND a > 2 AND a < 5
  5. ID:WHERE ID = 1
  6. ID范围:WHERE ID > 1 AND ID < 5
  7. 在仅搜索a或仅搜索b时,将使用此索引:WHERE a = 2; WHERE b = 3

    所选列可以是IDab的任意组合 - 如果列数较多,则索引不够,引擎必须从表中读取它们。

    搜索时可以使用(a, b) include (id)上的第二个索引:

    1. a,b:WHERE a = 2 AND b = 3
    2. a,范围b:WHERE a = 2 AND b > 3 AND b < 5
    3. a:WHERE a = 2
    4. 范围:WHERE a > 2 AND a < 5
    5. 在仅搜索ID或仅搜索b时,将使用此索引:WHERE ID = 1; WHERE b = 3

      所选列也可以是IDab的任意组合 - 如果有更多列,则索引不够,引擎必须从表中读取它们

      如果ID上存在聚簇索引,那么将ID作为INCLUDE添加到非聚集索引是没有意义的,因为聚簇列包含在每个非聚簇索引中隐含索引。这就是为什么通常建议使用窄聚簇索引,通常是4字节int。聚集索引越宽,每个非聚集索引所需的空间就越多。

      因此,(a, b) include (id)上的索引与您案例中的(a, b)相同。

      我不确定引擎是否足够聪明,如果明确INCLUDE ID,则不会浪费磁盘空间。这很容易检查。