為什麼同一張表有不必要的 2 索引連接?
我有一張名為
$$ Job $$有2個索引如下。(由於機密性,我不能用確切的名字發布整個執行計劃,對此感到抱歉。)
[IX_Job_WillTest] : (ColA ASC, ColB ASC) INCLUDE (ColC, ColD, ColE...(a lot more)) [missing_index_613_612] : (ColA ASC, ColB ASC) INCLUDE (ColC)
當我執行查詢時,查詢計劃顯示為圖片:
您可以看到 2 個索引彼此連接。但是,如上所述,索引
$$ IX_Job_WillTest $$具有查詢所需的所有列。為什麼 SQL 會費心加入索引$$ missing_index_613_612 $$. 我認為 SQL 這樣做沒有任何好處。 任何人都可以幫我解釋一下嗎?
我知道這個問題不清楚,因為我無法發布整個執行計劃(由於機密資訊)。誰能提出一些可能性,為什麼 SQL 會做出這個決定?十分感謝。
PS:數據庫是 Azure SQL 數據庫。
更新: 大家好,我已經簡化了查詢,隱藏了一些機密細節。這是查詢和計劃。問題是,為什麼 SQL 選擇加入 2 個索引,而它只能使用索引 IX_Job_WillTest?!為什麼要這麼浪費精力?!
SQL Server(以及因此 Azure SQL 數據庫)具有基於成本的查詢優化器 (QO)。這意味著它會生成許多邏輯上等效但物理上不同的查詢執行計劃,然後根據一些內部專有的成本計算模型選擇最便宜的一個。因此,很簡單,它選擇了這種雙索引連接,因為這比它考慮的任何替代計劃都便宜。
那麼問題就變成了為什麼這比使用單個索引更便宜。為了獲得準確的答案,我們需要表定義、統計資訊和查詢計劃。但是我願意假設。
這兩個索引具有相同的鍵(ColA、ColB),但包含的列不同。這意味著“缺失”更窄,頁面上可以容納更多行。因此,與“WillTest”相比,從“缺失”中讀取給定數量的行需要更少的 IO。SQL Server 的成本模型假設所有數據讀取都來自磁碟,因此如果能夠滿足手頭的需求,則優先讀取更窄的索引。我猜這個查詢有關於 ColA、ColB 和/或 ColC 的謂詞,並且使用“missing”是滿足這些條件的最便宜的方法。
為什麼然後拉入“WillTest”。我的猜測是該表中的更多列需要滿足查詢 - 無論是在謂詞中還是作為返回值。找到這些的最便宜的方法是在“WillTest”的 INCLUDES 中。另一種方法是讀取可能比“WillTest”更寬且讀取成本更高的基表。
您可以使用表格提示測試我的猜測。請注意查詢的總成本,就像現在一樣。然後提示它只使用一個索引,然後只使用另一個,注意每個索引的成本。我認為目前的計劃成本最低。然而,成本是一個黑匣子,因此這可能並不引人注目。
另一種解釋是您有一個索引交集。
你稱之為“不必要的”加入。可能不是。每個索引都有助於滿足查詢的需要。點擊每個 Index Seek 並按 F4(屬性)。謂詞和定義的列將顯示每個部分所扮演的角色。通過加入索引來做到這一點只是一種可能的實現方式。其他是可能的。QO 認為這是最便宜的。
最後請注意,優化過程至少有可能以某種非終端方式出錯,這只是它手頭執行的最不壞的計劃。
您是否在複製/粘貼索引建議?
你可能不想要那個。
您可能應該放棄
missing_index_613_612
,因為它們實際上是相同的。至於為什麼以這種方式建構計劃,您應該嘗試發布整個查詢,但是看到那個索引名稱,這可能是我最不擔心的事情。