Sql-Server

什麼時候可以在生產程式碼的查詢中使用索引提示?

  • March 14, 2020

我最近一直在使用大小合適的表(從 100 萬行到 100 億行之間),並且遇到了一些我被迫使用查詢提示的情況,我曾經認為這是不好的做法但自從得知他們有自己的位置(主要是 ForceSeek 和 ForceScan 提示)。

我終於遇到了一個查詢,無論我做什麼,我似乎都無法讓它自然地使用更好的索引(這是主鍵聚集索引)。

查詢非常簡單:

SELECT A.Field1, B.Field2
FROM TableA AS A WITH (FORCESEEK)
INNER JOIN TableB AS B WITH (FORCESEEK)
   ON A.PrimaryKeyClusteredIndexedField = B.PrimaryKeyClusteredIndexedField
WHERE B.NonClusteredIndexedField = SomeBooleanValue -- SomeBooleanValue = 1 (True)

我在許多數據庫(大約 500 個——這正是我們的架構的設計方式)上執行此查詢,並且在相對較小的數據庫中,它預設使用查詢計劃中的主鍵聚集索引。在幾個一次性更大的數據庫中,它嘗試在非聚集索引欄位“B.NonClusteredIndexedField”上執行索引查找,這也需要密鑰查找。

不知道為什麼在這種情況下它會選擇非聚集索引而不是主鍵聚集索引,但是鍵查找會嚴重影響查詢的性能。在 TableB 上使用索引提示,這樣程式碼就可以INNER JOIN TableB AS B WITH (FORCESEEK, INDEX(IX_PrimaryKeyClusteredIndex))解決這個問題,但我覺得很髒。是否可以在這樣的一次性情況下使用,尤其是當它是不太可能改變的主鍵聚集索引的索引提示時?

只有在不存在更好的解決方案時才可以這樣做。

正如大衛布朗 - 微軟評論的那樣:

如果你正在用另一種語言寫作,你不會三思而後行地告訴電腦,而不僅僅是告訴電腦**如何去做。這就是優化器提示的全部內容。

在該特定查詢上,您可以強制排序或顯式使用循環連接。但是FORCESEEK在 TableA 上的案例提示沒有任何意義:

SELECT A.Field1, B.Field2
FROM TableA AS A
INNER LOOP JOIN TableB AS B WITH (FORCESEEK)
   ON A.PrimaryKeyClusteredIndexedField = B.PrimaryKeyClusteredIndexedField
WHERE B.NonClusteredIndexedField = SomeBooleanValue

SELECT A.Field1, B.Field2
FROM TableA AS A
INNER JOIN TableB AS B WITH (FORCESEEK)
   ON A.PrimaryKeyClusteredIndexedField = B.PrimaryKeyClusteredIndexedField
WHERE B.NonClusteredIndexedField = SomeBooleanValue
OPTION(FORCE ORDER)

要在查詢提示中使用聚集索引,我建議使用它的編號而不是它的名稱:

SELECT A.Field1, B.Field2
FROM TableA AS A (FORCESEEK)
INNER LOOP JOIN TableB AS B WITH (FORCESEEK, INDEX(1))
   ON A.PrimaryKeyClusteredIndexedField = B.PrimaryKeyClusteredIndexedField
WHERE B.NonClusteredIndexedField = SomeBooleanValue

如果我們談論除聚集索引之外的任何索引,我通常會同意索引名稱更好。我已經看到聚集索引的不同名稱。一個名字完全不自我記錄的情況並不少見。使用索引 1,您至少可以確定使用聚集索引。

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