1. 程式人生 > >mysql InnoDB索引原理

mysql InnoDB索引原理

平衡多路查詢樹(B-Tree)

B-Tree是為磁碟等外儲存裝置設計的一種平衡查詢樹樹,在將B-Tree前先了解下磁碟相關知識。 系統從磁碟讀取資料到記憶體時是以磁碟塊為基本單位的,位於同一個磁碟塊的資料會被一次性取出,而不是需要什麼取什麼。 InnoDB儲存引擎中有頁(page)的概念,頁是其磁碟管理的最小單位。InnoDB儲存引擎中預設每個頁大小為16kb,可通過引數innodb_page_size將頁的大小設定為4K、8K、16K,在MySQL中可通過如下命令檢視頁的大小: mysql> show variables like ‘innodb_page_size’;

而系統一個磁碟塊的儲存空間往往沒有那麼大,因此InnoDB每次申請磁碟空間時都會是若干地址連續磁碟塊來達到頁的大小16KB。InnoDB在把磁碟資料讀入到記憶體時會以頁為基本單位,在查詢資料時如果一個頁中的每條資料都能有助於定位資料記錄的位置,這將會減少磁碟I/O次數,提高查詢效率。

B-Tree結構的資料可以讓系統高效的找到資料所在的磁碟塊。為了描述B-Tree,首先定義一條記錄為一個二元組[key, data] ,key為記錄的鍵值,對應表中的主鍵值,data為一行記錄中除主鍵外的資料。對於不同的記錄,key值互不相同。

一棵m階的B-Tree有如下特性:

  1. 每個節點最多有m個孩子。
  2. 除了根節點和葉子節點外,其它每個節點至少有Ceil(m/2)個孩子。
  3. 若根節點不是葉子節點,則至少有2個孩子
  4. 所有葉子節點都在同一層,且不包含其它關鍵字資訊
  5. 每個非終端節點包含n個關鍵字資訊(P0,P1,…Pn, k1,…kn)
  6. 關鍵字的個數n滿足:ceil(m/2)-1 <= n <= m-1
  7. ki(i=1,…n)為關鍵字,且關鍵字升序排序。
  8. Pi(i=1,…n)為指向子樹根節點的指標。P(i-1)指向的子樹的所有節點關鍵字均小於ki,但都大於k(i-1)

B-Tree中的每個節點根據實際情況可以包含大量的關鍵字資訊和分支,如下圖所示為一個3階的B-Tree: 在這裡插入圖片描述 每個節點佔用一個盤塊的磁碟空間,一個節點上有兩個升序排序的關鍵字和三個指向子樹根節點的指標,指標儲存的是子節點所在磁碟塊的地址。兩個關鍵詞劃分成的三個範圍域對應三個指標指向的子樹的資料的範圍域。以根節點為例,關鍵字為17和35,P1指標指向的子樹的資料範圍為小於17,P2指標指向的子樹的資料範圍為17~35,P3指標指向的子樹的資料範圍為大於35。 模擬查詢關鍵字29的過程:

1、’根據根節點找到磁碟塊1,讀入記憶體。【磁碟I/O操作第1次】 2、比較關鍵字29在區間(17,35),找到磁碟塊1的指標P2。 3、根據P2指標找到磁碟塊3,讀入記憶體。【磁碟I/O操作第2次】 4、比較關鍵字29在區間(26,30),找到磁碟塊3的指標P2。 5、根據P2指標找到磁碟塊8,讀入記憶體。【磁碟I/O操作第3次】 6、在磁碟塊8中的關鍵字列表中找到關鍵字29。

分析上面過程,發現需要3次磁碟I/O操作,和3次記憶體查詢操作。由於記憶體中的關鍵字是一個有序表結構,可以利用二分法查詢提高效率。而3次磁碟I/O操作是影響整個B-Tree查詢效率的決定因素。B-Tree相對於AVLTree縮減了節點個數,使每次磁碟I/O取到記憶體的資料都發揮了作用,從而提高了查詢效率。

B+Tree

B+Tree是在B-Tree基礎上的一種優化,使其更適合實現外儲存索引結構,InnoDB儲存引擎就是用B+Tree實現其索引結構。

從上一節中的B-Tree結構圖中可以看到每個節點中不僅包含資料的key值,還有data值。而每一個頁的儲存空間是有限的,如果data資料較大時將會導致每個節點(即一個頁)能儲存的key的數量很小,當儲存的資料量很大時同樣會導致B-Tree的深度較大,增大查詢時的磁碟I/O次數,進而影響查詢效率。在B+Tree中,所有資料記錄節點都是按照鍵值大小順序存放在同一層的葉子節點上,而非葉子節點上只儲存key值資訊,這樣可以大大加大每個節點儲存的key值數量,降低B+Tree的高度。

B+Tree相對於B-Tree有幾點不同: 1、非葉子節點只儲存鍵值資訊。 2、所有葉子節點之間都有一個鏈指標。 3、資料記錄都存放在葉子節點中。

將上一節中的B-Tree優化,由於B+Tree的非葉子節點只儲存鍵值資訊,假設每個磁碟塊能儲存4個鍵值及指標資訊,則變成B+Tree後其結構如下圖所示: 在這裡插入圖片描述

通常在B+Tree上有兩個頭指標,一個指向根節點,另一個指向關鍵字最小的葉子節點,而且所有葉子節點(即資料節點)之間是一種鏈式環結構。因此可以對B+Tree進行兩種查詢運算:一種是對於主鍵的範圍查詢和分頁查詢,另一種是從根節點開始,進行隨機查詢。

可能上面例子中只有22條資料記錄,看不出B+Tree的優點,下面做一個推算:

InnoDB儲存引擎中頁的大小為16KB,一般表的主鍵型別為INT(佔用4個位元組)或BIGINT(佔用8個位元組),指標型別也一般為4或8個位元組,也就是說一個頁(B+Tree中的一個節點)中大概儲存16KB/(8B+8B)=1K個鍵值(因為是估值,為方便計算,這裡的K取值為〖10〗3)。也就是說一個深度為3的B+Tree索引可以維護103 * 10^3 * 10^3 = 10億 條記錄。

實際情況中每個節點可能不能填充滿,因此在資料庫中,B+Tree的高度一般都在24層。mysql的InnoDB儲存引擎在設計時是將根節點常駐記憶體的,也就是說查詢某一鍵值的行記錄時最多隻需要13次磁碟I/O操作。

資料庫中的B+Tree索引可以分為聚集索引(clustered index)和輔助索引(secondary index)。上面的B+Tree示例圖在資料庫中的實現即為聚集索引,聚集索引的B+Tree中的葉子節點存放的是整張表的行記錄資料。輔助索引與聚集索引的區別在於輔助索引的葉子節點並不包含行記錄的全部資料,而是儲存相應行資料的聚集索引鍵,即主鍵。當通過輔助索引來查詢資料時,InnoDB儲存引擎會遍歷輔助索引找到主鍵,然後再通過主鍵在聚集索引中找到完整的行記錄資料。