前兩篇文章我總結了一些SQL資料庫索引的問題,這篇主要來分析下索引的優缼點,以及如何正確使用索引。
索引的優點:這個顯而易見,正確的索引會大大提高資料查詢,對結果進行排序、分組的操作效率。
索引的缺點:優點顯而易見,同樣缺點也是顯而易見:
1:建立索引需要額外的磁碟空間,索引最大一般為表大小的1.2倍左右。
2:在表資料修改時,例如增加,刪除,更新,都需要維護索引表,這是需要系統開銷的。
3:不合理的索引設計非但不能利於系統,反而會使系統效能下降。例如我們在一個建立有非叢集索引的列上做範圍查詢,此列的索引不會起到任何的最佳化效果,反而由於資料的修改而需要維護索引表,從而影響了對資料修改的效能。
實際例子:還是拿前兩篇文章的學生表來講吧,要查詢成績在50分以上的學生資訊select * from student where score>50。學生表包含了100000行記錄,而且學分是隨機產生的,這樣從資料量以及資料分布上都有一定的保障。
第一種情況:學生表有索引。
1:存在叢集索引,但叢集索引不在學分上,這裡只分析學分不是叢集索引的情況。
(1):學分上沒有索引。此時SQL會通過叢集索引來尋找資料,這點估計大家都會知道。
(2):學分上有索引。這種情況,SQL會使用上學分上的索引嗎?這個問題估計不是每個人都能回答正確的。既然學分上有索引,而where中又有此列,理應使用了索引,但實際情況並沒有使用索引。因為出現了範圍尋找,如果一個索引一個索引的比較,在效能上比起直接按叢集索引尋找全部資料後再過濾來的差。那學分上的索引什麼時候 SQL會優先考慮呢?當score指定為一個具體值時,就能使用學分索引尋找了。從的SQL執行計畫可以得知。
2:不存在叢集索引。
(1):在學分上沒有索引,其它欄位有索引,這種情況就會出現表掃描。
(2):在學分上有索引,是否會按照學分上的索引進行尋找呢?由於上面的表資料量也不少,一般會認為SQL不會採用表掃描,因為會尋找全部記錄,但實際情況表明SQL對於範圍查詢也行採用表掃描而不是按學生索引查詢。我們也可以強制SQL按學分查詢,於是有下面的SQL執行計畫比較,我們可以清楚的看出,強制使用學分做為索引查詢比表搜尋的效能要差很多。
第二種情況:學生表沒有索引。這個情況沒有分析的價值。
什麼欄位不適合建立索引?
1:不經常使用的列,這種索引帶來缺點遠大於帶來的優點。
2:邏輯性的欄位,例如性別欄位等等,匹配的記錄太多,和表掃描比起來不相上下。
3:欄位內容特別大的欄位,例如text等,這會大大增大索引所佔用的空間以及索引更新時的速度。
我們說SQL在維護索引時要消耗系統資源,那麼SQL維護索引時究竟消耗了什麼資源?會產生哪些問題?究竟怎樣才能最佳化欄位的索引?
第一:當資料頁達到了8K(資料頁最大為8K) 容量,如此時發生插入或更新資料的操作,將導致頁的分裂。
1、叢集索引的情況下:叢集索引將被插入和更新的行指向特定的頁,該頁由叢集索引關鍵字決定;
2、只有堆的情況下:有空間就可以插入新的行,對行資料的更新需要更多的空間,如果大於了當前頁的可用空間,行就被移到新的頁中,且在原位置留下一個轉寄指標,指向被移動的新行,如果具有轉寄指標的行又被移動了,那麼原來的指標將重新指向新的位置;
3、堆中有非叢集索引,儘管插入和更新操作,不會發生頁分裂,但非叢集索引上仍然產生頁分裂。
總結:無論有無索引,很多資料將保留在老頁面,其它將放入新頁面,並且新頁面可能被分配到任何可用的頁,頻繁頁分裂,表會產生大量資料片段,直接造成I/O 效率下降。
引出問題:為什麼資料庫對於varchar最大值設定為8000,而不是10000呢?
答:是由於資料頁大小最大為8K。
第二:針對上述索引可能造成的頁分頁的解決方案,填滿因數。
建立索引時,可以為索引指定一個填滿因數,在索引的每個葉級頁面上保留一定百分比的空間,將來資料可以進行擴充和減少頁分裂。值從0到100的百分比數值,100 時表示將資料頁填滿。不對資料變更時(例如唯讀表中)才用此設定,實用價值不大。值越小則資料頁上的空閑空間越大,可以減少在索引增長過程中進行頁分裂,但需要佔用更多的硬碟空間。填滿因數也不能設定過小,過小會影響SQL的讀取效能,因為填滿因數造成資料頁的增多。一般我們公司設定的填滿因數是80。
索引是否是一塵不變的?
隨著業務的變化,資料的變化,會發生有些索引的用處可能發生變化,例如:
1:原來主要靠使用者名稱搜尋記錄,現在業務更改為按使用者所在城市搜尋等等,此時我們需要即時變更表索引以適應新業務的變化,即資料和使用模式發生了大幅度變化。
2:系統上線前不合理的索引,隨著資料的增加,缺點越來越明顯,此時需要調整索引。
3:隨著資料的增加,產生了越來越多的頁分裂,導致索引效能越來越低。
上面的幾種情況,我們就需要選擇重建索引來徹底解決問題。
總結索引使用原則:
1:不要索引資料量不大的表,對於小表來講,表掃描的成本並不高。
2:不要設定過多的索引,在沒有叢集索引的表中,最大可以設定249個非叢集索引,過多的索引首先會帶來更大的磁碟空間,而且在資料發生修改時,對索引的維護是特別消耗效能的。
3:合理應用複合索引,有某些情況下可以考慮建立包含所有輸出資料行的覆蓋索引。
4:對經常使用範圍查詢的欄位,可能考慮叢集索引。
5:避免對不常用的列,邏輯性列,大欄位列建立索引。
有說的不對的地方,歡迎大家指正。
作者:薑敏
出處:http://www.cnblogs.com/aspnet2008/