复合主键中包含的列是否需要单独的索引?

Int*_*eXX 3 index foreign-key primary-key many-to-many

我有这个 M2M 连接表:

CREATE TABLE [dbo].[RecipientsDonors]
(
  [RecipientId] [int] NOT NULL,
  [DonorId] [int] NOT NULL,
  CONSTRAINT [PK_RecipientsDonors] PRIMARY KEY CLUSTERED 
  (
    [RecipientId] ASC,
    [DonorId] ASC
  )
)
Run Code Online (Sandbox Code Playgroud)

我也有这两个索引:

CREATE NONCLUSTERED INDEX [IX_RecipientsDonors_RecipientId] ON [dbo].[RecipientsDonors]
(
  [RecipientId] ASC
)

CREATE NONCLUSTERED INDEX [IX_RecipientsDonors_DonorId] ON [dbo].[RecipientsDonors]
(
  [DonorId] ASC
)
Run Code Online (Sandbox Code Playgroud)

我使用这两个索引的目的是加快单列查找速度。

既然主键存在,那么索引是否是多余的呢?或者它们是必要的,因为主键包含两列?

Cha*_*ace 6

索引始终只能由前导键使用。因此IX_RecipientsDonors_RecipientId索引并不是真正必要的,因为主键已经涵盖了相同的列。

虽然它会稍微提高单列扫描的性能(由于索引稍微窄一些),但这种扫描的可能性很低(如果可以查找,为什么还要扫描?),并且仅查询单列的可能性很低反正。此外,在每次插入、更新和删除时保持索引与表保持同步还存在索引成本,以及存储和备份索引的存储成本。

DROP INDEX [IX_RecipientsDonors_RecipientId] ON dbo.RecipientsDonors;
Run Code Online (Sandbox Code Playgroud)

IX_RecipientsDonors_DonorId然而,另一个索引应该保留。这对于对该列进行常规查找是必要的,而且因为每当删除父表行时,它将在外键查找中大量使用。

但明智的做法是向其中添加另一列,以便您可以完全涵盖寻求DonorId但想要RecipientId结果的查询。它也应该是唯一的,以便编译器可以推断优化。

这应该是您创建的每个两列多对多联接表的正常设置:两列上都有一个主键,以及一个辅助唯一索引,其中键列的顺序相反。

CREATE UNIQUE NONCLUSTERED INDEX [IX_RecipientsDonors_DonorId] ON dbo.RecipientsDonors
  (DonorId, RecipientId)
WITH (DROP_EXISTING = ON);
Run Code Online (Sandbox Code Playgroud)