SQL 服务器索引排序

SQL Server Indexing Ordering

我有一个table如下

CREATE TABLE [dbo].[VideoRecipient](
    [Id] [bigint] IDENTITY(1,1) NOT NULL,
    [UserId] [int] NOT NULL,
    [IssueId] [bigint] NOT NULL,
    [CreatedDateTime] [datetime2](7) NOT NULL,
    [NotifiedDateTime] [datetime2](7) NULL,
    [ReceivedDateTime] [datetime2](7) NULL,
    [ReadDateTime] [datetime2](7) NULL,
    [AcknowledgedDateTime] [datetime2](7) NULL,
    [IsDeleted] [bit] NOT NULL,
    [DeletedDateTime] [datetime2](7) NULL,
 CONSTRAINT [PK_VideoRecipient] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
))

然后我创建一个索引如下

CREATE NONCLUSTERED INDEX UX_VideoRecipient_UserId_IssueId_CreatedDateTime ON [dbo].VideoRecipient ([UserId], [IssueId], [CreatedDateTime]) INCLUDE ([ReadDateTime], [ReceivedDateTime], [AcknowledgedDateTime], [NotifiedDateTime])

当我通过 UserId 进行查询以获取记录时,它使用索引并使用索引查找,这正是我想要的。 如果我随后进行查询以通过 IssueId 获取记录,它会执行较慢的索引扫描。除了创建另一个索引并将 IssueId 指定为索引的第一列之外,是否有办法使索引成为搜索而不是扫描?

指定索引的第一列似乎比我原先想象的更重要!

索引实质上创建了另一个版本的 table,它只包含您提到的列。然后按照您指定的确切顺序对其进行排序(在您的示例中,它的顺序为 UserId->IssueId->CreatedDateTime)。由于索引中的 IssueId 列排在第二位,这意味着如果这是您要搜索的主要值,则这些值将不会按顺序排列。因此,SQL 必须对索引中的所有行执行 'scan' 才能找到您要搜索的项目。

如果您打算仅搜索 IssueId,则需要调整索引。如果您计划有多个查询来搜索不同的值,那么您将需要不同的索引。

但是请记住,向 table 添加索引会稍微减慢插入和更新的速度,因为在提交更改之前需要同时更新索引。因此,您需要确保创建索引是因为您需要它,而不是 "just in case".

([UserId], [IssueId], [CreatedDateTime]) 上创建的索引仅当您在

上进行查询过滤时才有用
  • 用户名
  • UserId, IssueId
  • UserId, CreatedDateTime
  • UserId、IssueId、CreatedDateTime

如果您只搜索 UserId,则不应将其他 fields 添加为 key fields

您不能使用此索引在 IssueIdCreatedDateTime 上进行搜索,因为它们不是 index 最左键字段 .

在添加与您创建的类似的 index 之前您应该三思:您的 index 具有原始 table 所有列 ,这意味着您只是 复制了 它。但是,如果您查看 nonclustered indexsize,您会发现它 甚至比原来的 table 更大。对于小表来说这可能不是问题,但对于大表来说确实是个问题。

如果您的大部分查询都在 UserId 上搜索,您可能会考虑重构您的 clustered index:它应该定义在用于大部分搜索的列上,PK 可以定义为 nonclustered.

index 的另一个问题完全复制了您的 table任何字段的任何更新 会导致您的 index已更新,它会减慢您的数据修改速度。