Order By 導致對大表進行掃描
我有以下查詢;
SELECT TOP 100 ID FROM [dbo].[TableName] WITH (NOLOCK) WHERE TypeId = 2 AND DateTimeUTC < '2022-Aug-04 07:02:40' AND DateTimeUTC > '4/26/2022 7:36:36 AM' ORDER BY ID ASC
桌子
$$ dbo $$.$$ TableName $$(不是它的真名,順便說一句)有超過 1.18 億行。 我在這個表上創建了以下索引;
CREATE INDEX [ix_TableName_DateTimeUTC_TypeId] ON [dbo].[TableName] (DateTimeUTC, TypeId) WITH FILLFACTOR = 90;
如果我執行此查詢(不包括
ORDER BY
),該查詢會在上述索引上執行 SEEK,並立即完成。但是,只要我包含ORDER BY
,查詢就會在 PK 上執行 SCAN,讀取所有 118+ 百萬行。可以想像,這會降低性能,並且查詢需要很長時間才能完成。解決此問題的最簡單方法是完全刪除該
ORDER BY
子句,但是我認為這是不可能的,因為應用程序(進行此呼叫)需要按順序返回數據。關於如何改進這一點的任何建議?
出擊
我會將索引更改為如下所示:
CREATE INDEX [TypeId_Id_DateTimeUTC] ON [dbo].[TableName] ( TypeId, Id, DateTimeUTC ) WITH ( FILLFACTOR = 100, SORT_IN_TEMPDB = ON );
這個想法是使初始數據位置和排序自由,並且還支持範圍謂詞。我在這些部落格文章中詳細討論了這一點:
讓我們一起設計一個 SQL Server 索引第 1部分、第 2部分、第 3 部分。
實際上,避免排序通常比使用殘差謂詞要好。
您應該對日期時間文字使用一致的明確格式。
>
和<
謂詞有兩種完全不同的格式是很奇怪的。
DateTimeUTC, TypeId
不是該索引的最佳順序。應首先列出相等條件中使用的列,因此如果此索引專門用於優化該查詢,則應首先列出 TypeId (
TypeId, DateTimeUTC
)。否則最好的辦法是在日期部分和剩余謂詞上進行範圍搜尋。如果您確實進行了索引更改並且仍然看到對聚集索引的掃描,這可能是因為 SQL Server 認為從已經按所需順序擁有它們的源中讀取它們並丟棄不匹配的索引比它更快在執行時對它們進行排序。由於
TOP 100
它只需要找到前 100 個匹配,然後就可以停止掃描。您可能與此處的問題類似,其中日期在很大程度上與它相關
id
而不是獨立於它,因此它低估了在id
找到與謂詞匹配的 100 之前需要按順序讀取的行。假設
ID
是一個升序的標識列,並且假設您的DateTimeUTC
謂詞今天結束,匹配的行可能都在索引的末尾,而不是均勻地分散在整個索引中,所以這幾乎是最壞的情況。要查看的可能查詢提示是
DISABLE_OPTIMIZER_ROWGOAL
從TOP``FORCESEEK