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
。
您不能使用此索引在 IssueId
或 CreatedDateTime
上进行搜索,因为它们不是 index
的 最左键字段 .
在添加与您创建的类似的 index
之前您应该三思:您的 index
具有原始 table
的 所有列 ,这意味着您只是 复制了 它。但是,如果您查看 nonclustered index
的 size
,您会发现它 甚至比原来的 table
更大。对于小表来说这可能不是问题,但对于大表来说确实是个问题。
如果您的大部分查询都在 UserId
上搜索,您可能会考虑重构您的 clustered index
:它应该定义在用于大部分搜索的列上,PK 可以定义为 nonclustered
.
index
的另一个问题完全复制了您的 table
是 任何字段的任何更新 会导致您的 index
已更新,它会减慢您的数据修改速度。
我有一个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
。
您不能使用此索引在 IssueId
或 CreatedDateTime
上进行搜索,因为它们不是 index
的 最左键字段 .
在添加与您创建的类似的 index
之前您应该三思:您的 index
具有原始 table
的 所有列 ,这意味着您只是 复制了 它。但是,如果您查看 nonclustered index
的 size
,您会发现它 甚至比原来的 table
更大。对于小表来说这可能不是问题,但对于大表来说确实是个问题。
如果您的大部分查询都在 UserId
上搜索,您可能会考虑重构您的 clustered index
:它应该定义在用于大部分搜索的列上,PK 可以定义为 nonclustered
.
index
的另一个问题完全复制了您的 table
是 任何字段的任何更新 会导致您的 index
已更新,它会减慢您的数据修改速度。