索引工作原理

 

爲什麼需要索引(Why is it needed)?

當數據保存在磁盤類存儲介質上時,它是作爲數據塊存放。這些數據塊是被當作一個整體來訪問的,這樣可以保證操作的原子性。硬盤數據塊存儲結構類似於鏈表,都包含數據部分,以及一個指向下一個節點(或數據塊)的指針,不需要連續存儲。

 

記錄集只能在某個關鍵字段上進行排序,所以如果需要在一個無序字段上進行搜索,就要執行一個線性搜索(Linear Search)的過程,平均需要訪問N/2的數據塊,N是表所佔據的數據塊數目。如果這個字段是一個非主鍵字段(也就是說,不包含唯一的訪問入口),那麼需要在N個數據塊上搜索整個表格空間。

 

但是對於一個有序字段,可以運用二分查找(Binary Search),這樣只要訪問log2 (N)的數據塊。這就是爲什麼性能能得到本質上的提高。

 

什麼是索引(What is indexing)?

索引是對記錄集的多個字段進行排序的方法。在一張表中爲一個字段創建一個索引,將創建另外一個數據結構,包含字段數值以及指向相關記錄的指針,然後對這個索引結構進行排序,允許在該數據上進行二分法排序。

 

副作用是索引需要額外的磁盤空間,對於MyISAM引擎而言,這些索引是被統一保存在一張表中的,這個文件將很快到達底層文件系統所能夠支持的大小限制,如果很多字段都建立了索引的話。

 

索引如何工作(How does it work?)

首先,我們建立一個示範數據庫表:

 

字段名       數據類型      大小

id (Primary key) Unsigned INT   4 bytes

firstName        Char(50)       50 bytes

lastName         Char(50)       50 bytes

emailAddress     Char(100)      100 bytes

注意:使用char是爲了指定準確的磁盤佔用大小。這個示範數據庫包含500萬行,而且沒有索引。我們將分析一些查詢語句的性能,一個是使用主鍵id(有序)查詢,一個是使用firstName(非關鍵無序字段)。

 

例1

 

我們的示範數據庫有r=5,000,000條記錄,每條記錄長度R=204字節而且使用MyISAM引擎存儲(默認數據塊大小爲B=1024字節),這張表的塊因子(blocking factor)會是bfr = (B/R) = 1024/204 = 5 條記錄每磁盤數據塊。保存這張表所需要的磁盤塊爲N = (r/bfr) = 5000000/5 = 1,000,000 blocks。

 

在id字段上的線性搜索平均需要N/2 = 500,000塊訪問來找到一條記錄假設id字段是查詢關鍵值,不過既然id字段是有序的,可以執行一個二分查詢,這樣平均只需要訪問log2 (1000000) = 19.93 = 20 個數據塊。我們馬上就看到了極大的提高。

 

現在firstName字段既不是有序的,無法執行二分搜索,數值也不具有唯一性,所以對這張表的查找必須到最後一個記錄即全表掃描N = 1,000,000個數據塊訪問。這就是索引用來改進的地方。

 

假如索引記錄只包含一個索引列以及一個指向原記錄數據的指針,那麼它顯而易見會比原記錄(多列)要小。所以索引本身所需要的磁盤塊要更少,掃描數目也少。firstName索引表結構如下:

 

Field name       Data type      Size on disk

firstName        Char(50)       50 bytes

(record pointer) Special        4 bytes

注意: MySQL裏的指針按表大小的不同分別可能是 2, 3, 4 或 5 個字節。

 

例2

 

假設我們的數據庫有r = 5,000,000 條記錄,建立了一個長R = 54字節的索引,並且使用默認磁盤塊大小爲1,024字節。那麼該索引的塊因子爲bfr = (B/R) = 1024/54 = 18 條記錄每磁盤塊。容納這個索引表總共需要的磁盤塊爲N = (r/bfr) = 5000000/18 = 277,778 塊。

 

現在使用FirstName字段來進行搜索就可以利用索引來提高性能。這允許使用一個二分查找,平均log2 (277778) = 18.08 -> 19次數據塊訪問。找到實際記錄的地址,這需要進一步的塊讀取,這樣總數達到19 + 1 = 20次數據塊訪問,這和非索引表的數據塊訪問次數有天壤之別。

 

什麼時候使用索引(When should it be used?)

鑑於創建索引需要額外的磁盤空間(上面的例子需要額外的277778個磁盤塊),以及太多的索引會導致文件系統大小限制所產生的問題,所以對哪些字段建立索引,什麼情況下使用索引,需要審慎考慮。

 

由於索引只是用來加速數據查詢,那麼顯然對只是用來輸出的字段建立索引會浪費磁盤空間以及發生插入、刪除操作時的處理時間,所以這種情況下應該儘量避免。此外鑑於二分搜索的特性,數據的基數或獨立性是很重要的。在基數爲2的字段上建立索引,將把數據分割一半,而基數爲1000則將返回大約1000條記錄。低基數的二分查找效率將降低爲一個線性排序,而且查詢優化器可能會在基數小於記錄數某個比例時(如30%)的情況下將避免使用索引而直接查詢原表,所以這種情況下的索引浪費了空間。

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