索引的基本原理(2)

二.填充因子 

 

然而在“混沌之初”,就可以在一定程度上避免不愉快出現,在創建索引時,可以爲這個索引指定一個填充因子,以便在索引的每個葉級頁面上保留一定百分比的空間,將來數據可以進行擴充和減少頁分裂。填充因子是從0100的百分比數值,設爲100時表示將數據頁填滿,只有當不會對數據進行更改時(例如只讀表中)才用此設置。值越小則數據頁上的空閒空間越大,這樣可以減少在索引增長過程中進行頁分裂的需要,但這一操作需要佔用更多的硬盤空間。 

 

填充因子只在創建索引時執行,索引創建以後,當表中進行數據的添加、刪除或更新時,是不會保持填充因子的,如果想在數據頁上保持額外的空間,則有悖於使用填充因子的本意,因爲隨着數據的輸入,SQLS必須在每個頁上進行頁拆分,以保持填充因子指定的空閒空間。因此,只有在表中的數據進行了較大的變動,纔可以填充數據頁的空閒空間。這時,可以從容的重建索引,重新指定填充因子,重新分佈數據。 

 

反之,填充因子指定不當,就會降低數據庫的讀取性能,其降低量與填充因子設置值成反比。例如,當填充因子的值爲50時,數據庫的讀取性能會降低兩倍。所以,只有在表中根據現有數據創建新索引,並且可以預見將來會對這些數據進行哪些更改時,設置填充因子纔有意義。 

 

三.兩道數學題 

 

假定數據庫設計沒有問題,那麼是否像上篇分析的那樣,當你建立了衆多的索引,在查詢工作中SQLS就只能按照“最高指示”用索引處理每一個提交的查詢呢?答案是否定的。

實際上,SQLS幾乎完全是“自主”的決定是否使用索引或使用哪一個索引。 

 

 

這是怎麼回事呢? 

 

讓我們先來算一道題:如果某表的一條記錄在磁盤上佔用1000字節(1K)的話,我們對其中10字節的一個字段建立索引,那麼該記錄對應的索引大小隻有10字節(0.01K)。上篇說過,SQLS的最小空間分配單元是“頁(Page)”,一個頁面在磁盤上佔用8K空間,所以一頁只能存儲8條“記錄”,但可以存儲800條“索引”。現在我們要從一個有8000條記錄的表中檢索符合某個條件的記錄(Where子句),如果沒有索引的話,我們需要遍歷8000條×1000字節/8K字節=1000個頁面才能夠找到結果。如果在檢索字段上有上述索引的話,那麼我們可以在8000條×10字節/8K字節=10個頁面中就檢索到滿足條件的索引塊,然後根據索引塊上的指針逐一找到結果數據塊,這樣I/O訪問量肯定要少得多。 

 

然而有時用索引比不用索引還快。 

 

同上,如果要無條件檢索全部記錄(不用Where子句),不用索引的話,需要訪問8000條×1000字節/8K字節=1000個頁面;而使用索引的話,首先檢索索引,訪問8000條×10字節/8K字節=10個頁面得到索引檢索結果,再根據索引檢索結果去對應數據頁面,由於是檢索全部數據,所以需要再訪問8000條×1000字節/8K字節=1000個頁面將全部數據讀取出來,一共訪問了1010個頁面,這顯然不如不用索引快。 

 

SQLS內部有一套完整的數據索引優化技術,在上述情況下,SQLS會自動使用表掃描的方式檢索數據而不會使用任何索引。那麼SQLS是怎麼知道什麼時候用索引,什麼時候不用索引的呢?因爲SQLS除了維護數據信息外,還維護着數據統計信息。 

 

四.統計信息 

 

打開企業管理器,單擊“Database”節點,右擊Northwind數據庫→單擊“屬性”→選擇“Options”選項卡,觀察“Settings”下的各項複選項,你發現了什麼? 

 

Settings中我們可以看到,在數據庫中,SQLS將默認的自動創建和更新統計信息,這些統計信息包括數據密度和分佈信息,正是它們幫助SQLS確定最佳的查詢策略:建立查詢計劃和是否使用索引以及使用什麼樣的索引。 

 

在創建索引時,SQLS會創建分佈數據頁來存放有關索引的兩種統計信息:分佈表和密度表。查詢優化器使用這些統計信息估算使用該索引進行查詢的成本(Cost),並在此基礎上判斷該索引對某個特定查詢是否有用。 

 

隨着表中的數據發生變化,SQLS自動定期更新這些統計信息。採樣是在各個數據頁上隨機進行。從磁盤讀取一個數據頁後,該數據頁上的所有行都被用來更新統計信息。統計信息更新的頻率取決於字段或索引中的數據量以及數據更改量。比如,對於有一萬條記錄的表,當1000個索引鍵值發生改變時,該表的統計信息便可能需要更新,因爲1000 個值在該表中佔了10%,這是一個很大的比例。而對於有1千萬條記錄的表來說,1000個索引值發生更改的意義則可以忽略不計,因此統計信息就不會自動更新。 

 

五.索引的人工維護 

 

上面講到,某些不合適的索引將影響到SQLS的性能,隨着應用系統的運行,數據不斷地發生變化,當數據變化達到某一個程度時將會影響到索引的使用。這時需要用戶自己來維護索引。 

 

隨着數據行的插入、刪除和數據頁的分裂,有些索引頁可能只包含幾頁數據,另外應用在執行大量I/O的時候,重建非聚聚集索引可以維護I/O的效率。重建索引實質上是重新組織B樹。需要重建索引的情況有: 

 

1.數據和使用模式大幅度變化; 

 

2.排序的順序發生改變; 

 

3.要進行大量插入操作或已經完成; 

 

4.使用I/O查詢的磁盤讀次數比預料的要多; 

 

5.由於大量數據修改,使得數據頁和索引頁沒有充分使用而導致空間的使用超出估算; 

 

6dbcc檢查出索引有問題。

 

六.索引的使用原則 

 

接近尾聲的時候,讓我們再從另一個角度認識索引的兩個重要屬性----惟一性索引和複合性索引。 

 

惟一性索引保證在索引列中的全部數據是惟一的,不會包含冗餘數據。如果表中已經有一個主鍵約束或者惟一性約束,那麼當創建表或者修改表時,SQLS自動創建一個惟一性索引。但出於必須保證惟一性,那麼應該創建主鍵約束或者惟一性鍵約束,而不是創建一個惟一性索引。 

 

複合索引就是一個索引創建在兩個列或者多個列上。在搜索時,當兩個或者多個列作爲一個關鍵值時,最好在這些列上創建複合索引。當創建複合索引時,應該考慮這些規則:最多可以把16個列合併成一個單獨的複合索引,構成複合索引的列的總長度不能超過900字節;在複合索引中,所有的列必須來自同一個表中,不能跨表建立複合列;在複合索引中,列的排列順序是非常重要的,原則上,應該首先定義最惟一的列,例如在(COL1COL2)上的索引與在(COL2COL1)上的索引是不相同的,因爲兩個索引的列的順序不同;爲了使查詢優化器使用複合索引,查詢語句中的WHERE子句必須參考複合索引中第一個列。 

 

綜上所述,我們總結了如下索引使用原則: 

 

1.邏輯主鍵使用惟一的成組索引,對系統鍵(作爲存儲過程)採用惟一的非成組索引,對任何外鍵列採用非成組索引。考慮數據庫的空間有多大,表如何進行訪問,還有這些訪問是否主要用作讀寫; 

 

2.不要索引memo/note 字段,不要索引大型字段(有很多字符),這樣作會讓索引佔用太多的存儲空間; 

 

3.不要索引常用的小型表; 

 

4.一般不要爲小型數據表設置過多的索引,如果經常有插入和刪除操作就更不要設置索引,因爲SQLS對插入和刪除操作提供的索引維護可能比掃描表空間消耗的時間更多。 

 

查詢是一個物理過程,表面上是SQLS在東跑西跑,其實真正大部分壓馬路的工作是由磁盤輸入輸出系統(I/O)完成,全表掃描需要從磁盤上讀表的每一個數據頁,如果有索引指向數據值,則I/O讀幾次磁盤就可以了。但是,在隨時發生的增、刪、改操作中,索引的存在會大大增加工作量,因此,合理的索引設計是建立在對各種查詢的分析和預測上的,只有正確地使索引與程序結合起來,才能產生最佳的優化方案。 

 

SQLS是一個很複雜的系統,讓索引以及查詢背後的東西真相大白,可以幫助我們更爲深刻的瞭解我們的系統。一句話,索引就像鹽,少則無味多則鹹。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章