Sql-Server

SSMS 缺失索引功能建議的這兩個索引是否應該合併?

  • December 30, 2015

我正在嘗試提高實體框架自動生成的特定查詢的性能。我已經通過 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
)

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])

我沒有發布我正在優化的查詢,因為它非常可怕(由實體框架生成)並且幾乎不可讀。通常,查詢會查找 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])
       )

這似乎歸結為

WHERE PackageID=@PackageID AND IsSynchronized=0

好吧,你可以考慮一個過濾索引——如果你總是在尋找IsSynchronized = 0這個數字應該相對較小的行,那麼不要考慮這兩個索引,而是考慮這個:

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

當然,如果查詢必須查找數據(如果行數很少,應該非常有效),您可能希望將其變得更小並測試以查看影響的差異,所以 - 假設PackageID是集群鍵:

CREATE NONCLUSTERED INDEX [IX_NotSynchronized] 
 ON [dbo].[PackageEvents] ([PackageID])
 WHERE IsSynchronized = 0;

與完整索引相比,維護此索引的成本可能非常值得節省空間,特別是如果它僅用於優化此查詢(或至少查詢模式)。

不過,過濾索引並不神奇。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]);

(很長一段時間我都認為在密鑰中包含 BIT 列很浪費,但 Martin Smith 展示了一個效果很好的案例 - 值得一試。我現在找不到文章了。)

如果沒有您的完整架構、數據、查詢模式等,我們只能指導您並讓您在您的環境中測試我們的建議。我們不能說,“叮!這是適合你的!”

引用自:https://dba.stackexchange.com/questions/78486