[SQL SERVER] 多個索引 vs 單一寬索引

[SQL SERVER] 多個索引 vs 單一寬索引

實務上最快提高查詢效能莫過於建立和設計正當索引,

依照相關TSQL建立設計正確索引所帶來效能效益我個人認為是最高的,

這篇來討論一個索引設計問題,

我們知道大部分情況下index seek優於index scan(大海撈針),

假設今天有一TSQL如下(where 條件有三個):

 

設計1:依照條件建立三個nonclustered index

因為需要使用index join,所以TSQL改寫如下

 

 

執行計畫

image

雖然一開始都個別使用index seek 運算子,但hash join運算子成本高的可怕,

並且出現遺漏索引警告。

 

統計資料

image

 

設計2:個別建立三個篩選索引(SQL2008後提供)

 

執行計畫

image

整體執行計畫和設計1相差不多(少了點陣圖運算子),但依然還是可以看到hash join高成本和遺漏索引資訊。

ps:以這篩選索引來說少了彈性,只要查詢條件一有改變,篩選索引馬上無用武之地,

如果資料表沒有其他索引的話將導致出現無法建立執行計畫錯誤。

 

統計資料

image

使用篩選索引降低很多I/O和CPU。

 

設計3:建立單一寬索引 with include

 

執行計畫

image

執行計畫複雜度降低,而且也沒有任何遺漏索引訊息,但是依然還是使用平行執行計畫。

 

 

統計資料

image

I/O和CPU都有比面兩種設計來的低很多。

 

設計3.1:建立單一寬索引 without include

 

ps:執行計畫和統計資料都和設計3相同,但是該索引大小比設計3來的大,

效率比設計3來的低(acid問題)。

 

 

設計4:建立單一篩選索引

 

執行計畫

image

執行計畫不複雜是我們樂於看到的結果。

 

 

統計資料

image

I/O邏輯讀取目前是最低的,不過這篩選索引設計缺點前面有提到過了(缺乏彈性)。

 

調校

為了兼具彈性和效能,我決定從設計3下手調校,設計3執行計畫可看到是使用平行計畫,

查看該執行計劃發現最大問題在於資料型別不同所導致,

因為設計4執行計畫只有單一索引搜尋運算子,換句話說該執行計畫或許是最佳執行計畫,

修正TSQL並執行設計3索引

 

 

執行計畫

image

執行計畫和設計4相同。

 

 

統計資料

image

雖然I/O和CPU不如設計4來的優,但卻比設計4來的更有彈性,同時也比原本設計3更好。

 

 

結論:

1.盡量避免使用 Hint

現在SQL Server query optimize 比以前好太多,大部分情況下無需使用Hint來強制改變執行計畫,

當然Hint還是有存在價值,如果查詢有使用hint建議每個月或每一季再次確認執行計畫是否有所改變。

 

2.單一寬索引是比較好選擇

建立多個索引並透過index join將導致高CPU和I/O,這意味者增加資源競爭,

同時單一資料表中索引過多會影響新增、修改、刪除效能,

而這也表示可能帶來更多長lock問題

 

3.資料欄為請使用include

非索引鍵資料行可大幅降低I/O,因為可以不需存取資料表或Clustered Index,

便可直接在Nonclustered Index找到所有資料行,

同時可降低索引大小、而且Database Engine也不會考慮非索引鍵資料行大小(16個資料行、900bytes限制),

可說一舉多得。

 

4.是否需要Indexed View

索引設計中這也是需要考慮的,你可以參考我以前文章來決定是否需要

[SQL SERVER][Performance]善用Indexed View#1簡介

[SQL SERVER][Performance]善用Indexed View#2測試

 

5.索引鍵順序

雖然很多人都說順序不是那麼重要,但我個人認為到目前為止還是有那麼一些差異存在,

個人習慣把直接相等述詞排在最前面,如果述詞相同,則比較資料類型優先權(高的在前面),

如果資料類型相同,在比較長度大小(長度小的在前面)。

 

 

 

 

參考

邏輯與實體運算子參考

資料類型優先順序 (Transact-SQL)