使用FORCESEEK表進行高階優化

iSQlServer發表於2008-12-22

FORCESEEK 表提示強制查詢優化器僅使用索引查詢操作作為訪問查詢引用的表或者檢視中的資料的路徑。 您可使用該表提示覆蓋查詢優化器選擇的預設計劃,從而避免因低效的查詢計劃而導致的效能問題。 例如,如果計劃中包含表掃描運算子或者索引掃描運算子,且相應的表導致執行查詢期間讀取十分頻繁,如 STATISTICS IO 輸出中所示,則強制索引查詢操作可能會獲得更好的查詢效能。 如果優化器因基數或開銷估計不準確而在編譯計劃時傾向於選擇掃描操作,則更是如此。

FORCESEEK 適用於聚集索引查詢和非聚集索引查詢操作。 可以在 SELECT 語句的 FROM 子句和 UPDATE 或 DELETE 語句的 FROM 子句中為任何表或檢視指定 FORCESEEK。

注意:
由於 SQL Server 查詢優化器通常會為查詢選擇最優執行計劃,因此我們建議,只有在最後迫不得已的情況下才可由資深的開發人員和資料庫管理員使用提示。
 


 評估查詢計劃對 FORCESEEK 的適用性
如果查詢計劃對錶或檢視使用表掃描或索引掃描運算子,FORCESEEK 表提示可能有用,但索引查詢運算子可能更為高效。 請考慮以下查詢和後續執行計劃。

 複製程式碼
USE AdventureWorks;
GO
SELECT *
FROM Sales.SalesOrderHeader AS h
INNER JOIN Sales.SalesOrderDetail AS d
    ON h.SalesOrderID = d.SalesOrderID
WHERE h.TotalDue > 100
AND (d.OrderQty > 5 OR d.LineTotal < 1000.00);
GO

下列執行計劃顯示查詢優化器選擇了聚集索引掃描運算子來訪問兩個表中的資料。


如下列查詢所示,可通過指定 FORCESEEK 提示強制查詢優化器對 Sales.SalesOrderDetail 表執行查詢操作。

 複製程式碼
USE AdventureWorks;
GO
SELECT *
FROM Sales.SalesOrderHeader AS h
INNER JOIN Sales.SalesOrderDetail AS d WITH (FORCESEEK)
    ON h.SalesOrderID = d.SalesOrderID
WHERE h.TotalDue > 100
AND (d.OrderQty > 5 OR d.LineTotal < 1000.00);
GO


下列執行計劃顯示了在查詢中使用 FORCESEEK 提示的結果。 聚集索引查詢操作被用來訪問 Sales.SalesOrderDetail 表中的資料。


支援索引並集和交集
FORCESEEK 提示支援索引並集和交集。 此提示使查詢優化器更可能使用這些技術。 為了避免延長簡單查詢的編譯時間,通常僅在根據將列的基數和選擇性考慮在內的規則時才會選擇索引並集和交集。 不過,指定 FORCESEEK 提示後,會跳過此類規則,而始終將這些技術考慮在內。 例如,考慮以下查詢:

 複製程式碼
SELECT * FROM T WITH(FORCESEEK) WHERE T.a = 1 AND T.b = 2;
如果表 T 中的列 a 和列 b 具有單獨的非聚集索引,則可選擇索引交集計劃。 也就是說,此計劃包含對列 a 的非聚集索引查詢操作和對列 b 的非聚集索引查詢操作,並且在對基表執行查詢操作之前對所得的索引鍵集求交集。

下例中選擇了一個索引並集計劃。 也就是說,計劃包含對列 a 的查詢操作和對列 b 的查詢操作,並且在對基表執行查詢操作之前對所得的索引鍵集求並集。

 複製程式碼
SELECT * FROM T WITH(FORCESEEK) WHERE T.a = 1 OR T.b = 2;
對使用 LIKE 或 IN 的查詢應用 FORCESEEK
當查詢將 IN 或 LIKE 用做搜尋謂詞時,查詢優化器規則和不準確的基數估計也會導致優化器執行表掃描或索引掃描操作,而不是索引查詢操作。

下面的示例演示將 LIKE 或 IN 用做搜尋謂詞時,FORCESEEK 提示如何強制查詢優化器執行索引查詢操作,而不是表掃描操作。 若要檢視查詢執行計劃,請在執行此示例前單擊“包括實際的執行計劃”工具欄按鈕。

 複製程式碼
USE tempdb;
GO
DROP TABLE t;
GO
CREATE TABLE t(i int UNIQUE, j int, vc varchar(100));
CREATE INDEX t_vc ON t(vc);
GO
DECLARE @p1 int, @p2 int, @p3 int, @p4 int, @p5 int;
SELECT * FROM t WHERE i IN (@p1, @p2, @p3, @p4, @p5);
GO
DECLARE @p1 int, @p2 int, @p3 int, @p4 int, @p5 int;
SELECT * FROM t WITH (FORCESEEK) WHERE i IN (@p1, @p2, @p3, @p4, @p5);
GO
SELECT * FROM t WHERE vc LIKE 'Test%';
GO
SELECT * FROM t WITH (FORCESEEK) WHERE vc LIKE 'Test%';
GO
DECLARE @vc varchar(100);
SELECT * FROM t WHERE vc LIKE @vc;
GO
DECLARE @vc varchar(100);
SELECT * FROM t WITH (FORCESEEK) where vc like @vc;
GO
 對檢視使用 FORCESEEK
指定 FORCESEEK 時有無索引提示均可。 將 FORCESEEK 表提示應用到某一檢視或索引檢視時,FORCESEEK 提示將遞迴傳播到該檢視擴充套件版本中的所有表。 如果已指定索引提示,則會將其忽略。 如果並非每個基礎表都至少包含一個索引,則無法找到計劃並返回錯誤 8622。

對索引檢視的引用同時使用 FORCESEEK 和 NOEXPAND 提示時,則使用此索引檢視時無需事先將其展開。 FORCESEEK 提示將直接應用到索引檢視,這與處理表的方式相同。

如果將 FORCESEEK 提示應用至表引用,則表引用無法參與索引檢視匹配。 但是,查詢中其他不受 FORCESEEK 提示影響的部分可參與索引檢視匹配。 這一點與使用 INDEX 提示時索引檢視匹配的行為是相似的。

 最佳做法注意事項
以下為建議的最佳做法:

在使用 FORCESEEK 表提示之前,請確保資料庫中的統計資訊是最新的,且準確無誤。
最新的統計資訊有助於優化器實現對不同查詢計劃的開銷的準確估算,並選擇高質量的計劃。 因此,建議對於每個使用者資料庫,都將 AUTO_CREATE_STATISTICS 和 AUTO_UPDATE_STATISTICS 設定為 ON(預設值)。 或者,您可以使用 UPDATE STATISTICS 語句手動更新表或檢視的統計資訊。

評估查詢看其是否存在可能導致不準確基數估計或開銷估計的項,如果可能則刪除這些項。 例如,用引數或文字替換區域性變數並限制查詢中多語句表值函式和表變數的使用。 有關要查詢的其他項的更多資訊,請參閱 Microsoft SQL Server 2005 中查詢優化器使用的統計資訊。

除非在必要情況下,否則請不要將 INDEX 提示與 FORCESEEK 一起使用。 也就是說,如果單獨使用 FORCESEEK 就可生成滿足需要的計劃,則同時使用 INDEX 提示會過分限制優化器可做的選擇。 而且,在更改表的物理架構以刪除 INDEX 提示中指定的索引時,此提示將導致查詢失敗。 相比之下,只要應用 FORCESEEK 提示的表中至少存在一個可使用的索引,則即使在您更改索引結構時查詢仍能編譯。

請不要將 INDEX 提示 INDEX (0) 與 FORCESEEK 提示一起使用。 INDEX (0) 強制對基表進行掃描。 在與 FORCESEEK 同時使用時,將無法找到計劃並返回錯誤 8622。

請不要將 USE PLAN 查詢提示與 FORCESEEK 提示一起使用。 否則,將忽略 FORCESEEK 提示。

 

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/16436858/viewspace-520808/,如需轉載,請註明出處,否則將追究法律責任。

相關文章