模擬真實數據。生成大型表格(最終表格的大小應與您在現實生活中期望的大小相同),並按照您在現實生活中的預期分配產品和日期。首先在產品上添加三個獨立的索引,開始日期,結束日期。嘗試運行查詢。分析執行計劃。嘗試其他索引組合。比較計劃和表現。如果沒有東西給出可接受的性能,請使用生成示例數據和查詢的腳本返回。
在我的測試中,優化器是三個獨立索引搜索的內部連接結果。
創建表
加三爲每列索引無關:
CREATE TABLE [dbo].[Test](
[ID] [int] IDENTITY(1,1) NOT NULL,
[ProductID] [int] NOT NULL,
[StartDate] [date] NOT NULL,
[EndDate] [date] NOT NULL,
CONSTRAINT [PK_Test] PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
CREATE NONCLUSTERED INDEX [IX_EndDate] ON [dbo].[Test]
(
[EndDate] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
CREATE NONCLUSTERED INDEX [IX_ProductID] ON [dbo].[Test]
(
[ProductID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
CREATE NONCLUSTERED INDEX [IX_StartDate] ON [dbo].[Test]
(
[StartDate] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
生成測試數據總
- 1M行。
- 多達100個具有統一分佈的不同產品ID。
- 開始日期內萬天從2000-01-01(〜27年的時間跨度)
- 結束日期爲達到1000天,從開始日期(病程可達〜3年)
查詢:
INSERT INTO Test(ProductID, StartDate, EndDate)
SELECT TOP(1000000)
CA.ProductID
,DATEADD(day, StartOffset, '2000-01-01') AS StartDate
,DATEADD(day, StartOffset+DurationDays, '2000-01-01') AS EndDate
FROM
sys.all_objects AS o1
cross join sys.all_objects AS o2
cross apply
(
SELECT
cast((cast(CRYPT_GEN_RANDOM(4) as int)/4294967295.0 + 0.5) * 100 + 1 as int) AS ProductID
,cast((cast(CRYPT_GEN_RANDOM(4) as int)/4294967295.0 + 0.5) * 10000 as int) AS StartOffset
,cast((cast(CRYPT_GEN_RANDOM(4) as int)/4294967295.0 + 0.5) * 1000 as int) AS DurationDays
) AS CA
查詢優化:
DECLARE @VarDate date = '2004-01-01';
SELECT *
FROM Test
WHERE
ProductID = 1
AND @VarDate >= StartDate
AND @VarDate <= EndDate
;
它返回〜500行。
執行計劃
![plan](https://i.stack.imgur.com/B4I2Q.png)
服務器建議下列指數:
CREATE NONCLUSTERED INDEX [<Name of Missing Index, sysname,>]
ON [dbo].[Test] ([ProductID],[StartDate],[EndDate])
INCLUDE ([ID])
但具有這樣的指數是愚蠢,IMHO。
如果總共有1M行和100K個不同的產品ID,而不是100;換句話說,如果由特定產品ID搜索消除絕大部分的行,那麼最好的選擇是有可能對產品id一個索引,包括其他列進去:
CREATE NONCLUSTERED INDEX IX_Product
ON [dbo].[Test] ([ProductID])
INCLUDE ([StartDate],[EndDate])
OR
CREATE NONCLUSTERED INDEX IX_Product
ON [dbo].[Test] ([ProductID], [StartDate])
INCLUDE ([EndDate])
或
CREATE NONCLUSTERED INDEX IX_Product
ON [dbo].[Test] ([ProductID],[EndDate])
INCLUDE ([StartDate])
如果其中一個日期提供了很好的選擇性,那麼在它上面有一個索引而不是ProductID。
如果沒有色譜柱具有良好的選擇性,那麼它很難。
編輯
這是愚蠢的,盲目地做出一個索引優化器的建議,因爲你知道你將搜索特定的產品ID,但隨後的一系列StartDates,然後EndDates的範圍。所以,第三列EndDate永遠不會用於搜索本身。在這種情況下,索引中的這一列最好爲INCLUDE
,而不是如上所示將其作爲索引的一部分。
如果查詢的是特定的ProductID和特定的StartDate(不是範圍),那麼對於一個範圍的結束日期(或特定結束日期),然後將具有結束日期作爲指標,將有助於的一部分。
感謝您提供這些鏈接並突出顯示B-tree無法將其剪切爲空間連接。我將嘗試實施一個測試解決方案,將日期範圍強制爲空間兼容的數據類型,然後將性能與其他用戶建議的B樹索引進行比較。我選擇這個作爲最有用的答案,因爲它突出了與更有效的複合一維實現相反的多維方法。謝謝! – PkmnBugCatcher