從聚集索引中查找每個項目最早日期的最佳方法是什麼
我有一個 SQL Server 2012 表,其中包含如下列:
ID int NOT NULL, EventDate datetime NOT NULL, ... 32 other columns...
該表在大約 10000 個不同的 ID 值的範圍內有大約十億行。
該表有一個唯一的聚集索引,如下所示:
CREATE UNIQUE CLUSTERED INDEX [MyIndex] ON [dbo].[MyTable] ( [ID] ASC, [EventDate] ASC )
我需要找到最早的 per-ID EventDate,我可以使用以下查詢來獲取它:
SELECT ID, min(EventDate) FROM [dbo].[MyTable] GROUP BY ID
但是,此查詢只需不到 2 分鐘即可完成。
由於 NDA 限制,我無法分享我正在查看的問題的細節(查詢計劃等),但我可以建議我正在查看聚集索引掃描,因此它正在檢查表中的所有行。鑑於數據是按 EventDate 順序組織的,我希望檢索會更快,但我不確定如何。任何其他 ID 特定範圍查詢都會在幾毫秒內響應,並且該表最近已重建和重新索引,因此我認為沒有任何統計更新會有所幫助。
誰能建議一種更好的方法來確定每個 ID 的最小 EventDate 值,從而避免掃描整個聚集索引?
我確實有一個包含(10,000)個不同
id
值的表。
這與**“索引跳過掃描”優化有關(請參閱下面的連接項,從 2011 年開始)。不幸的是,它已被關閉為“不會修復”**。
一些相關的增強已經存在,但僅適用於分區表:分區表和索引的查詢處理增強。
但存在各種解決方法:
解決方法/解決方案 1:
CROSS APPLY
使用子查詢TOP 1
如果有一個具有 (10K) 個不同
ID
值的表,我們可以使用它來執行CROSS APPLY
.-- if you don't have a table already CREATE TABLE MyTableIDs ( ID int NOT NULL, PRIMARY KEY (id) ) ; -- we only do this once INSERT INTO MyTableIDs (ID) SELECT ID FROM MyTable GROUP BY ID ;
然後查詢將對索引執行 (10K) 搜尋:
SELECT i.ID, a.EventDate FROM MyTableIDs AS i CROSS APPLY ( SELECT TOP (1) t.EventDate FROM MyTable AS t WHERE t.ID = i.ID ORDER BY EventDate ) AS a ;
解決方法/解決方案 2:使用遞歸 CTE 實施“跳過掃描”
另一種選擇是使用遞歸 CTE 來實現跳過掃描。這是一個展示腳本,由 @PaulWhite 於 2010 年 10 月在 SSC 上發布,展示了 rCTE 可以多快:計算興趣查詢
在你的情況下,它會是這樣的:
WITH RecursiveCTE AS ( SELECT a.* FROM ( SELECT TOP (1) ID, EventDate FROM MyTable ORDER BY ID, EventDATE ) AS a UNION ALL SELECT r.ID, r.EventDate FROM ( -- A cunning way to use TOP in the recursive part of a CTE ;) SELECT t.ID, t.EventDate, rn = ROW_NUMBER() OVER (ORDER BY t.EventDate) FROM MyTable AS t JOIN RecursiveCTE AS r ON r.ID < t.ID ) AS r WHERE r.rn = 1 ) SELECT * FROM RecursiveCTE OPTION (MAXRECURSION 0) ;
解決方法/解決方案 3:分區表
如果您有企業版,則可用。連結文章中有關此可能性的更多詳細資訊:分區表和索引的查詢處理增強
主要缺點是跳過掃描僅
ID
在分區列時才有效。解決方法/解決方案 4:附加索引
添加 NCI 索引
(ID, EventDate)
允許對更小的索引進行索引掃描。有關解釋,請參閱@Daniel Hutmacher 的答案。它仍然是一個掃描,而不是(很多)搜尋,所以我不確定它是否會像選項 1 和 2 一樣好擴展。當然,一切都取決於細節(列大小、不同 ID 的數量與重複值的數量等) )。
解決方法/解決方案(不,不工作)5:索引視圖
好主意,如果可行的話。
GROUP BY
不幸的是,如果一個視圖有,則它不能被索引MIN/MAX
,請參閱索引視圖的限制。我想知道為什麼,因為如果它有
GROUP BY
and是允許的(並被索引)COUNT_BIG()
。也可能有一個關於它的 Connect 項目!解決方法/解決方案 6:“自己動手”索引視圖
自己實現一個等價於索引視圖。例如,您可以在(具有不同值的表,請參閱選項 1)中添加一
MinEventDate
列,並在該列中添加相應地更新此列的觸發器。那麼您的查詢將是一個簡單的 from 。MyTableIDs``ID``MyTable``SELECT``MyTableIDs
相關網頁的連結
- 連接項:實現索引跳過掃描
- 實現的功能:分區表和索引的查詢處理增強
- 索引視圖和限制:創建索引視圖