Sql-Server
了解高度獨特的 WHERE 子句的性能
我一直在努力了解如何處理在這種情況下經常出現的特定類型的性能問題:當您想在查詢中應用多個過濾器時,但您知道第一個過濾器將返回一個非常小的數字非常大的表中的行數。
例如,我們有一個包含 10M+ 行的 3rd 方異構表,其中的列根據
TYPEID
. 這是一個範例查詢:SELECT ID, NAME, INT109 FROM DATA WHERE TYPEID = 8301514 AND INT109 = 1
在此查詢中,兩個過濾器沒有覆蓋索引,但“TYPEID”列上有一個索引。令人困惑的是,即使在 10M 的表中只有大約 500 行,但
TYPEID = 8301514
這個查詢有時需要幾秒鐘才能執行。如果我只是在最後刪除
INT109 = 1
過濾器,查詢幾乎會立即執行:SELECT ID, NAME, INT109 FROM DATA WHERE TYPEID = 8301514
對我來說,使用更少的過濾器會使查詢執行得更快是沒有意義的。此外,行為似乎不一致 - 如果第一個查詢已經執行多次,它也可以執行得非常快,就像正在記憶體的東西一樣。很難進行可靠的實驗(這是在 SQL Azure 中)。這是正常行為嗎?這是否可能是由錯誤的執行計劃(即使我沒有使用參數)或過時的統計資訊引起的?
這裡可能發生的情況是,在某個時候,您執行第一個查詢時的值超過了 500 行 - 如此之多以至於它認為掃描 10M 行要比進行數十萬次查找來獲得更好的名稱和 INT109 列。然後,該計劃被記憶體,並在您提供不同的價值時重用,而該價值將受益於不同的計劃。SQL 假設避免重新編譯比評估您可以提供的每個不同值更好。
當您編寫不同的查詢時,它會重新評估它,並給出最佳計劃,儘管這對於不同的值可能不是理想的。
解決此問題的最佳方法是在 上設置一個索引
(TYPEID, INT109) INCLUDE (ID, Name)
,這樣就不需要查找,並且無論 TYPEID 周圍的統計資訊如何,該計劃都會搜尋。此外,即使您忽略 INT109,此索引也很有用。