Sql-Server

由於“SELECT *”的聚集表掃描

  • May 8, 2020

我有一個Records包含 100 多列和非常多行的表,以及基於我的訪問路徑的 5 個欄位的非聚集索引:

CREATE NONCLUSTERED INDEX [IX_Records_CustomerID]
ON [dbo].[Records] (
   [CustomerID] ASC, -- int
   [IsInvalid] ASC, -- int
   [IsProcessed] ASC, -- bit
   [IsRejected] ASC, -- bit
   [RecordName] ASC, -- varchar(12)
;

這5個欄位不包括主鍵RecordID,即聚集索引中的列。

這是我表現不佳的查詢:

SELECT * FROM Records WHERE CustomerID IN (181, 283, 505)

執行計劃顯示它執行聚集索引掃描,我理解這是因為我選擇了索引中未包含的列。在 Management Studio 中,我將查詢更改為:

SELECT CustomerID, IsInvalid, IsProcessed, IsRejected, RecordName FROM Records 
   WHERE CustomerID IN (181, 283, 505)

並且執行計​​劃顯示一個Index Seek,查詢執行時間從44秒下降到2秒。但是,我無法在應用程序中自由地*僅用我需要並已包含在我的索引中的列替換 。

當我被鎖定時,有什麼辦法可以繞過聚集索引掃描SELECT *

如果您需要輸出中未包含在索引中的列,則優化器必須做出選擇:

  1. 執行表/聚集索引掃描(因此所有列都在那裡)
  2. 執行查找,然後執行查找以檢索未涵蓋的列

它將選擇哪種方式取決於多種因素,包括索引有多窄,有多少行與謂詞匹配等。您可以使用FORCESEEK提示強制搜尋,但我懷疑它最終會執行相同或更差SQL Server 在您的情況下選擇的掃描。

一些選項:

  1. 更改應用程序以執行正確的查詢。我首先列出這個是有原因的
  2. 創建一個僅選擇您需要的列的視圖:
CREATE VIEW dbo.myview
WITH SCHEMABINDING
AS
 SELECT col1, col2, col3 FROM dbo.tablename;

然後,您可以SELECT *從此視圖更改應用程序。或者您可以更有創意並重命名原始表格,並將此視圖的名稱更改為表格的名稱。明顯的改變;謹慎行事。 3. 將所有其他列添加到索引的鍵或INCLUDE列表中。如果這些是硬編碼值並且總是使用的值,您可以考慮使用過濾索引。

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