Sql-Server

為什麼我的執行計劃顯示在使用專門使用非聚集索引的索引提示時正在發生聚集索引掃描?

  • October 10, 2020

幕後故事:

我有一個具有以下結構的表:

CREATE TABLE WideTable1
(
   BoringColumn1,
   BoringColumn2,
   CellPhoneNumberColumn Phone(VARCHAR(20)), -- User-defined types, see below
   PagerPhoneNumberColumn Phone(VARCHAR(20)), -- User-defined types, see below
   IsActive YN(CHAR(1)), -- User-defined types, see below
   BoringColumn3,
   ...
   BoringColumn350
)

使用此表的原始查詢是在 CellPhoneNumberColumn 和 PagerPhoneNumber 上執行一些 SQL 函式,然後稍後將這些函式的輸出用作另一個查詢中的謂詞。NULLIF(LTRIM(ISNULL(CellPhoneNumberColumn, PagerPhoneNumberColumn)))就是一個例子。

這些列也是所有使用者定義的類型,在這種情況下 CellPhoneNumberColumn 和 PagerPhoneNumberColumn 被定義為 UDT Phone(VARCHAR(20)),因此它們的基礎數據類型是VARCHAR(20)。IsActive 被定義為 YN(CHAR(1)) 所以它實際上是一個 CHAR(1)。

此外更複雜的是,這個表/數據庫的排序規則是Latin1_General_BIN.

長話短說,最初的消費查詢遇到了基數估計問題。為了緩解這個問題,我在上述列上創建了一個索引視圖,並使用以下定義將 SQL 函式應用於它們(*注意我沒有創建這個原始邏輯,只是試圖修復它的性能):

CREATE VIEW PhoneNumbersNormalized WITH SCHEMABINDING AS

SELECT 
   NULLIF(LTRIM(ISNULL(CAST(CellPhoneNumberColumn AS VARCHAR(20)), CAST(PagerPhoneNumberColumn AS VARCHAR(20)))) AS Cell,
   SUM(CASE WHEN CAST(IsActive AS CHAR(1)) = 'Y'THEN 1 ELSE 0 END) AS IsActive 
FROM dbo.WideTable1
GROUP BY NULLIF(LTRIM(ISNULL(CAST(CellPhoneNumberColumn AS VARCHAR(20)), CAST(PagerPhoneNumberColumn AS VARCHAR(20)))) 

我還在索引視圖 PhoneNumbersNormalized 上創建了以下索引:

CREATE UNIQUE CLUSTERED INDEX IXV_PhoneNumbersNormalized_Cell ON dbo.PhoneNumbersNormalized(Cell)
CREATE NONCLUSTERED INDEX IXV_NC_PhoneNumbersNormalized_Cell_IsActive ON  dbo.PhoneNumbersNormalized(Cell, IsActive)

問題: 當我從包含實際執行計劃的索引視圖 PhoneNumbersNormalized 中進行選擇時,我注意到執行計劃特別提到了原始基礎表 WideTable1 作為數據的來源。

此外,如果我從索引視圖中選擇 PhoneNumbersNormalized 並在執行計劃上方創建的非聚集索引上帶有索引提示,則IXV_NC_PhoneNumbersNormalized_PhoneNumber_IsActive顯示沒有提及正在使用此非聚集索引,而是說它正在執行聚集索引掃描(注意我混淆了原始表名,它在我的伺服器上實際上並不稱為 WideTable1): 執行計劃

粘貼的執行計劃: https ://www.brentozar.com/pastetheplan/?id=HJytxh2UP

為什麼執行計劃總是顯示原始基礎表而不是索引視圖,並且始終在基礎表上使用聚集索引,即使我對索引視圖的選擇查詢使用索引提示強制使用非聚集索引?

為什麼執行計劃總是顯示原始基礎表而不是索引視圖,並且始終在基礎表上使用聚集索引,即使我對索引視圖的選擇查詢使用索引提示強制使用非聚集索引?

您的視圖定義正在擴展。您將需要NOEXPAND提示。

我可以在非索引視圖上使用 NOEXPAND 提示嗎?

來自文件:查詢優化器將視圖視為具有聚集索引的表。NOEXPAND 僅適用於索引視圖。

模式綁定視圖是否將其具體化?

模式綁定是一種對象屬性,可以應用於視圖以外的事物,例如函式。但是,您不能索引未綁定架構的視圖。

有關函式的範例,請查看此問答:

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