SSMS 缺失索引功能建議的這兩個索引是否應該合併?
我正在嘗試提高實體框架自動生成的特定查詢的性能。我已經通過 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 展示了一個效果很好的案例 - 值得一試。我現在找不到文章了。)
如果沒有您的完整架構、數據、查詢模式等,我們只能指導您並讓您在您的環境中測試我們的建議。我們不能說,“叮!這是適合你的!”