SSMS 缺失索引功能建议的这两个索引是否应该合并?

Cas*_*ins 1 database-design sql-server index-tuning sql-server-2012

我正在尝试提高由实体框架自动生成的特定查询的性能。我已经通过 SSMS 运行了查询,它建议创建两个缺失的索引。有问题的表:

CREATE TABLE [dbo].[PackageEvents]
(
[EventID] [int] NOT NULL IDENTITY(1, 1),
[PackageID] [char] (24) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
[EventDescription] [varchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
[EventDate] [datetime] NOT NULL,
[UserName] [varchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
[Notes] [varchar] (max) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
[IsSynchronized] [bit] NOT NULL CONSTRAINT [DF_AmazonPackageEvents_IsSynchronized]  
  DEFAULT ((0)),
[LastSyncDate] [datetime] NULL,
[Version] [timestamp] NOT NULL
)
Run Code Online (Sandbox Code Playgroud)

SSMS 建议了以下两个索引:

CREATE NONCLUSTERED INDEX [IX_IsSynchronized] ON [dbo].[PackageEvents]  
([IsSynchronized]) INCLUDE ([PackageID])

CREATE NONCLUSTERED INDEX [IX_Covering] ON [dbo].[PackageEvents] ([PackageID])  
INCLUDE ([EventDate], [EventDescription], [EventID], [IsSynchronized], [LastSyncDate],  
[Notes], [UserName], [Version])
Run Code Online (Sandbox Code Playgroud)

我没有发布我正在优化的查询,因为它非常糟糕(由实体框架生成)并且几乎无法读取。通常,查询会查找 IsSynchronized = 0 的任何行并返回这些行。

有没有办法将这两个索引组合成一个索引,以提供相同或更好的性能优势?如果没有确切的查询,这个问题是不可能回答的吗?

编辑:唯一存在的索引是主键 EventID 上的聚集索引。

我搜索了生成的实体框架查询。以下 where 子句出现 4 次,但总是以相同的形式出现:

 WHERE  EXISTS (SELECT 
            1 AS [C1]
            FROM [dbo].[AmazonPackageEvents] AS [Extent46]
            WHERE ([Project30].[PackageID] = [Extent46].[PackageID]) AND  
           (0 = [Extent46].[IsSynchronized])
        )
Run Code Online (Sandbox Code Playgroud)

这似乎归结为

WHERE PackageID=@PackageID AND IsSynchronized=0
Run Code Online (Sandbox Code Playgroud)

Aar*_*and 5

好吧,你可以考虑一个过滤索引 - 如果你总是在寻找IsSynchronized = 0这个数字应该相对较小的行,那么不要考虑这两个索引,而是考虑这个:

CREATE NONCLUSTERED INDEX [IX_NotSynchronized] 
  ON [dbo].[PackageEvents] ([PackageID])  
  INCLUDE ([EventDate], [EventDescription], [EventID], 
    [LastSyncDate], [Notes], [UserName], [Version]) 
  WHERE IsSynchronized = 0;
Run Code Online (Sandbox Code Playgroud)

当然,如果查询必须查找数据(如果行数很小,应该非常有效),您可能希望使其更小并测试以查看影响的差异,因此 - 假设PackageID是聚类键:

CREATE NONCLUSTERED INDEX [IX_NotSynchronized] 
  ON [dbo].[PackageEvents] ([PackageID])
  WHERE IsSynchronized = 0;
Run Code Online (Sandbox Code Playgroud)

与完整索引相比,维护此索引的开销可能非常值得节省空间,特别是如果它仅用于优化此查询(或至少是查询模式)。

不过,过滤索引并不神奇。JNK 提出了以下一些限制:

使用过滤索引的注意事项 - 统计数据可能无法在没有维护的情况下保持最新,并且您需要对某些设置(如 QUOTED IDENTIFIER 和 ANSI NULLS)使用“标准”值。这些都是小问题,但如果您在插入索引的会话中设置错误,插入将失败。

您还需要阅读这些帖子:


如果您不想使用过滤索引,您可以测试这些变体:

CREATE NONCLUSTERED INDEX [IX_Covering_try1] ON [dbo].[PackageEvents] 
  ([PackageID], IsSynchronized)  
INCLUDE ([EventDate], [EventDescription], [EventID], 
  [LastSyncDate], [Notes], [UserName], [Version]);

CREATE NONCLUSTERED INDEX [IX_Covering_try2] ON [dbo].[PackageEvents] 
  (IsSynchronized, [PackageID])  
INCLUDE ([EventDate], [EventDescription], [EventID], 
  [LastSyncDate], [Notes], [UserName], [Version]);
Run Code Online (Sandbox Code Playgroud)

(很长一段时间以来,我认为在键中包含 BIT 列是一种浪费,但 Martin Smith 展示了一个效果很好的案例 - 值得一试。我现在找不到帖子了。)

如果没有您的完整架构、数据、查询模式等,我们只能指导您并让您在您的环境中测试我们的建议。我们不能说,“叮!这个对你有用!”

  • 使用过滤索引的注意事项 - 没有维护,统计数据可能不会保持最新,并且您需要对某些设置使用“标准”值,例如“QUOTED IDENTIFIER”和“ANSI NULLS”。这些都是小问题,但如果您在插入索引的会话中设置错误,插入将失败。 (2认同)