關於索引的B tree B-tree B+tree B*tree 詳解結構圖( 二)

索引分爲聚簇索引和非聚簇索引。

以一本英文課本爲例,要找第8課,直接翻書,若先翻到第5課,則往後翻,再翻到第10課,則又往前翻。這本書本身就是一個索引,即“聚簇索引”。

如果要找"fire”這個單詞,會翻到書後面的附錄,這個附錄是按字母排序的,找到F字母那一塊,再找到"fire”,對應的會是它在第幾課。這個附錄,爲“非聚簇索引”。

由此可見,聚簇索引,索引的順序就是數據存放的順序,所以,很容易理解,一張數據表只能有一個聚簇索引。

聚簇索引要比非聚簇索引查詢效率高很多,特別是範圍查詢的時候。所以,至於聚簇索引到底應該爲主鍵,還是其他字段,這個可以再討論。

1、MYSQL的索引

mysql中,不同的存儲引擎對索引的實現方式不同,大致說下MyISAM和InnoDB兩種存儲引擎。

MyISAM的B+Tree的葉子節點上的data,並不是數據本身,而是數據存放的地址。主索引和輔助索引沒啥區別,只是主索引中的key一定得是唯一的。這裏的索引都是非聚簇索引。

MyISAM還採用壓縮機制存儲索引,比如,第一個索引爲“her”,第二個索引爲“here”,那麼第二個索引會被存儲爲“3,e”,這樣的缺點是同一個節點中的索引只能採用順序查找。


InnoDB的數據文件本身就是索引文件,B+Tree的葉子節點上的data就是數據本身,key爲主鍵,這是聚簇索引。非聚簇索引,葉子節點上的data是主鍵(所以聚簇索引的key,不能過長)。爲什麼存放的主鍵,而不是記錄所在地址呢,理由相當簡單,因爲記錄所在地址並不能保證一定不會變,但主鍵可以保證。

至於爲什麼主鍵通常建議使用自增id呢?

2、聚簇索引

聚簇索引的數據的物理存放順序與索引順序是一致的,即:只要索引是相鄰的,那麼對應的數據一定也是相鄰地存放在磁盤上的。如果主鍵不是自增id,那麼可以想象,它會幹些什麼,不斷地調整數據的物理地址、分頁,當然也有其他一些措施來減少這些操作,但卻無法徹底避免。但,如果是自增的,那就簡單了,它只需要一頁一頁地寫,索引結構相對緊湊,磁盤碎片少,效率也高。

聚簇索引不但在檢索上可以大大滴提高效率,在數據讀取上也一樣。比如:需要查詢f~t的所有單詞。

一個使用MyISAM的主索引,一個使用InnoDB的聚簇索引。兩種索引的B+Tree檢索時間一樣,但讀取時卻有了差異。

因爲MyISAM的主索引並非聚簇索引,那麼他的數據的物理地址必然是凌亂的,拿到這些物理地址,按照合適的算法進行I/O讀取,於是開始不停的尋道不停的旋轉。聚簇索引則只需一次I/O。

不過,如果涉及到大數據量的排序、全表掃描、count之類的操作的話,還是MyISAM佔優勢些,因爲索引所佔空間小,這些操作是需要在內存中完成的。

鑑於聚簇索引的範圍查詢效率,很多人認爲使用主鍵作爲聚簇索引太多浪費,畢竟幾乎不會使用主鍵進行範圍查詢。但若再考慮到聚簇索引的存儲,就不好定論了。




學習筆記】mysql索引原理之B+/-Tree

索引,是爲了更快的查詢數據,查詢算法有很多,對應的數據結構也不少,數據庫常用的索引數據結構一般爲B+Tree。

1、B-Tree

關於B-Tree的官方定義個人覺得比較難懂,通俗一點就是舉個例子。假如:一本英文字典,單詞+詳細解釋組成了一條記錄,現在需要索引單詞,那麼以單詞爲key,單詞+詳細解釋爲data,B-Tree就是以一個二元組{key,data}來定義一條記錄。如果一個節點有3條記錄,那麼會有對應的4個指針,用以指向下一個節點。B-Tree是有序且平衡的,所有葉子節點在同一層,即不會出現某個分支層級多,某個分支層級少的情況。


因爲B-Tree是有序的,所以它的查找就簡單了,先從根節點開始二分查找,找到則返回節點;否則沿着區間指針查找下一個節點。比如,查詢false這個單詞。

2、B+Tree

與B-Tree不同的是,B+Tree每個節點只有key,沒有data;而且葉子節點沒有指針。也就是說B+Tree的葉子節點和內節點的數據結構是不一樣的。


一般數據庫採用的是B+Tree,而且經過了一些優化,比如在葉子節點上增加了順序訪問指針,提高區間查詢效率。比如:查詢首字母爲f~t的所有單詞。那麼只需查到f開頭的第一個單詞fabric,然後沿着葉子節點的開始遍歷,直到找到最後一個以t開頭的單詞爲止。


 

簡單介紹了B-/+Tree,至於衆多數據結構中,爲何數據庫索引選擇BTree,而且選擇B+Tree,下面從計算機存儲原理方面簡單說說。

3、讀內存和讀磁盤

內存讀取和磁盤讀取的效率是相差很大的。

簡單點說說內存讀取,內存是由一系列的存儲單元組成的,每個存儲單元存儲固定大小的數據,且有一個唯一地址。

當需要讀內存時,將地址信號放到地址總線上傳給內存,內存解析信號並定位到存儲單元,然後把該存儲單元上的數據放到數據總線上,回傳。

寫內存時,系統將要寫入的數據和單元地址分別放到數據總線和地址總線上,內存讀取兩個總線的內容,做相應的寫操作。

內存存取效率,跟次數有關,先讀取A數據還是後讀取A數據不會影響存取效率。而磁盤存取就不一樣了,磁盤I/O涉及機械操作。

磁盤是由大小相同且同軸的圓形盤片組成,磁盤可以轉動(各個磁盤須同時轉動)。磁盤的一側有磁頭支架,磁頭支架固定了一組磁頭,每個磁頭負責存取一個磁盤的內容。磁頭不動,磁盤轉動,但磁臂可以前後動,用於讀取不同磁道上的數據。磁道就是以盤片爲中心劃分出來的一系列同心環(如圖標紅那圈)。磁道又劃分爲一個個小段,叫扇區,是磁盤的最小存儲單元。


磁盤讀取時,系統將數據邏輯地址傳給磁盤,磁盤的控制電路會解析出物理地址,即哪個磁道哪個扇區。於是磁頭需要前後移動到對應的磁道,消耗的時間叫尋道時間,然後磁盤旋轉將對應的扇區轉到磁頭下,消耗的時間叫旋轉時間。所以,適當的操作順序和數據存放可以減少尋道時間和旋轉時間。

爲了儘量減少I/O操作,磁盤讀取每次都會預讀,大小通常爲頁的整數倍。即使只需要讀取一個字節,磁盤也會讀取一頁的數據(通常爲4K)放入內存,內存與磁盤以頁爲單位交換數據。因爲局部性原理認爲,通常一個數據被用到,其附近的數據也會立馬被用到。

4、檢索性能分析

B-Tree:如果一次檢索需要訪問4個節點,數據庫系統設計者利用磁盤預讀原理,把節點的大小設計爲一個頁,那讀取一個節點只需要一次I/O操作,完成這次檢索操作,最多需要3次I/O(根節點常駐內存)。數據記錄越小,每個節點存放的數據就越多,樹的高度也就越小,I/O操作就少了,檢索效率也就上去了。

B+Tree:內節點只存key,大大滴減少了內節點的大小,那麼每個節點就可以存放更多的記錄,樹的更矮了,I/O操作更少了。所以B+Tree擁有更好的性能。

5、其他索引方式

散列索引:通過HASH來定位的一種索引,這種索引用的較少,通過用於單值查詢。InnoDB的自適應索引就是HASH索引。

位圖索引:字段值固定且少,比如性別、狀態。在同時對多個這樣的字段and/or查詢時,效率極高,直接按位與/或就可以得到結果了。所以,應用範圍侷限。

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