B+/-Tree原理及mysql的索引分析
B+/-Tree原理
B-Tree介紹
B-Tree是一種多路搜尋樹(並不是二叉的):1.定義任意非葉子結點最多隻有M個兒子;且M>2;
2.根結點的兒子數為[2, M];
3.除根結點以外的非葉子結點的兒子數為[M/2, M];
4.每個結點存放至少M/2-1(取上整)和至多M-1個關鍵字;(至少2個關鍵字)
5.非葉子結點的關鍵字個數=指向兒子的指標個數-1;
6.非葉子結點的關鍵字:K[1], K[2], …, K[M-1];且K[i] < K[i+1];
7.非葉子結點的指標:P[1], P[2], …, P[M];其中P[1]指向關鍵字小於K[1]的子樹,P[M]指向關鍵字大於K[M-1]的子樹,其它P[i]指向關鍵字屬於(K[i-1], K[i])的子樹;
如:(M=3)
B-樹的特性:
1.關鍵字集合分佈在整顆樹中;
2.任何一個關鍵字出現且只出現在一個結點中;
3.搜尋有可能在非葉子結點結束;
4.其搜尋效能等價於在關鍵字全集內做一次二分查詢;
5.自動層次控制;
B-樹的搜尋,從根結點開始,對結點內的關鍵字(有序)序列進行二分查詢,如果命中則結束,否則進入查詢關鍵字所屬範圍的兒子結點;重複,直到所對應的兒子指標為空,或已經是葉子結點;
B+Tree介紹
B+樹是B-樹的變體,也是一種多路搜尋樹:
1.
2.非葉子結點的子樹指標與關鍵字個數相同;
3.非葉子結點的子樹指標P[i],指向關鍵字值屬於[K[i], K[i+1])的子樹(B-樹是開區間);
5.為所有葉子結點增加一個鏈指標;
6.所有關鍵字都在葉子結點出現;
如:(M=3)
B+的搜尋與B-樹也基本相同,區別是B+樹只有達到葉子結點才命中(B-樹可以在非葉子結點命中),其效能也等價於在關鍵字全集做一次二分查詢;
B+的特性:
1.所有關鍵字都出現在葉子結點的連結串列中(稠密索引),且連結串列中的關鍵字恰好是有序的;
2.不可能在非葉子結點命中;
3.非葉子結點相當於是葉子結點的索引(稀疏索引),葉子結點相當於是儲存(關鍵字)資料的資料層;
4.更適合檔案索引系統;
mysql中的索引
mysql中普遍使用B+Tree做索引,但在實現上又根據聚簇索引和非聚簇索引而不同。
聚簇索引
所謂聚簇索引,就是指主索引檔案和資料檔案為同一份檔案,聚簇索引主要用在Innodb儲存引擎中。在該索引實現方式中B+Tree的葉子節點上的data就是資料本身,key為主鍵,如果是一般索引的話,data便會指向對應的主索引,如下圖所示:在B+Tree的每個葉子節點增加一個指向相鄰葉子節點的指標,就形成了帶有順序訪問指標的B+Tree。做這個優化的目的是為了提高區間訪問的效能,例如圖4中如果要查詢key為從18到49的所有資料記錄,當找到18後,只需順著節點和指標順序遍歷就可以一次性訪問到所有資料節點,極大提到了區間查詢效率。
非聚簇索
非聚簇索引就是指B+Tree的葉子節點上的data,並不是資料本身,而是資料存放的地址。主索引和輔助索引沒啥區別,只是主索引中的key一定得是唯一的。主要用在MyISAM儲存引擎中,如下圖:
非聚簇索引比聚簇索引多了一次讀取資料的IO操作,所以查詢效能上會差。
MyisAM索引與InnoDB索引相比較
- MyisAM支援全文索引(FULLTEXT)、壓縮索引,InnoDB不支援;
- InnoDB支援事務,MyisAM不支援;
- MyisAM順序儲存資料,索引葉子節點儲存對應資料行地址,輔助索引很主鍵索引相差無幾;InnoDB主鍵節點同時儲存資料行,其他輔助索引儲存的是主鍵索引的值;
- MyisAM鍵值分離,索引載入記憶體(key_buffer_size),資料快取依賴作業系統;InnoDB鍵值一起儲存,索引與資料一起載入InnoDB緩衝池;MyisAM主鍵(唯一)索引按升序來儲存儲存,InnoDB則不一定
- MyisAM索引的基數值(Cardinality,show index 命令可以看見)是精確的,InnoDB則是估計值。這裡涉及到資訊統計的知識,MyisAM統計資訊是儲存磁碟中,在alter表或Analyze table操作更新此資訊,而InnoDB則是在表第一次開啟的時候估計值儲存在快取區內;
- MyisAM處理字串索引時用增量儲存的方式,如第一個索引是‘preform’,第二個是‘preformence’,則第二個儲存是‘7,ance’,這個明顯的好處是縮短索引,但是缺陷就是不支援倒序提取索引,必須順序遍歷獲取索引
為什麼選用B+/-Tree
一般來說,索引本身也很大,不可能全部儲存在記憶體中,因此索引往往以索引檔案的形式儲存的磁碟上。這樣的話,索引查詢過程中就要產生磁碟I/O消耗,相對於記憶體存取,I/O存取的消耗要高几個數量級,所以評價一個數據結構作為索引的優劣最重要的指標就是在查詢過程中磁碟I/O操作次數的漸進複雜度。換句話說,索引的結構組織要儘量減少查詢過程中磁碟I/O的存取次數。
簡單點說說記憶體讀取,記憶體是由一系列的儲存單元組成的,每個儲存單元儲存固定大小的資料,且有一個唯一地址。當需要讀記憶體時,將地址訊號放到地址總線上傳給記憶體,記憶體解析訊號並定位到儲存單元,然後把該儲存單元上的資料放到資料匯流排上,回傳。
寫記憶體時,系統將要寫入的資料和單元地址分別放到資料匯流排和地址總線上,記憶體讀取兩個匯流排的內容,做相應的寫操作。
記憶體存取效率,跟次數有關,先讀取A資料還是後讀取A資料不會影響存取效率。而磁碟存取就不一樣了,磁碟I/O涉及機械操作。磁碟是由大小相同且同軸的圓形碟片組成,磁碟可以轉動(各個磁碟須同時轉動)。磁碟的一側有磁頭支架,磁頭支架固定了一組磁頭,每個磁頭負責存取一個磁碟的內容。磁頭不動,磁碟轉動,但磁臂可以前後動,用於讀取不同磁軌上的資料。磁軌就是以碟片為中心劃分出來的一系列同心環(如圖示紅那圈)。磁軌又劃分為一個個小段,叫扇區,是磁碟的最小儲存單元。
磁碟讀取時,系統將資料邏輯地址傳給磁碟,磁碟的控制電路會解析出實體地址,即哪個磁軌哪個扇區。於是磁頭需要前後移動到對應的磁軌,消耗的時間叫尋道時間,然後磁碟旋轉將對應的扇區轉到磁頭下,消耗的時間叫旋轉時間。所以,適當的操作順序和資料存放可以減少尋道時間和旋轉時間。
為了儘量減少I/O操作,磁碟讀取每次都會預讀,大小通常為頁的整數倍。即使只需要讀取一個位元組,磁碟也會讀取一頁的資料(通常為4K)放入記憶體,記憶體與磁碟以頁為單位交換資料。因為區域性性原理認為,通常一個數據被用到,其附近的資料也會立馬被用到。
B-Tree:如果一次檢索需要訪問4個節點,資料庫系統設計者利用磁碟預讀原理,把節點的大小設計為一個頁,那讀取一個節點只需要一次I/O操作,完成這次檢索操作,最多需要3次I/O(根節點常駐記憶體)。資料記錄越小,每個節點存放的資料就越多,樹的高度也就越小,I/O操作就少了,檢索效率也就上去了。
B+Tree:非葉子節點只存key,大大滴減少了非葉子節點的大小,那麼每個節點就可以存放更多的記錄,樹更矮了,I/O操作更少了。所以B+Tree擁有更好的效能。