MySQL 索引採用B+樹的數據結構進行存儲,如下圖所示:
真實的數據存在於葉子節點,即3、5、9、10、13、15、28、29、36、60、75、79、90、99.
非葉子節點不存儲真實數據,只存儲指引搜索方向的數據項(指針),如17、35並不真實存在於數據表中。
索引的數據結構
一個磁盤相當於一個數據頁,B+樹的查找過程如下:
比如要查找數據項29:
首先會把磁盤塊1加載到內存中,此時發生一次IO,在內存中用二分法查找 確定29在17 和35之間,鎖定磁盤塊1的P2指針,內存處理時間相對比磁盤IO非常短,可以忽略不計。
然後通過磁盤塊1中的P2指針指向的地址把磁盤塊3加載到內存中,此時發生第二次IO,採用二分法確定29在26和30之間,鎖定磁盤塊3中的P2指針。
最後通過磁盤塊3中P2 指針指向的地址把磁盤塊8加載到內存中,此時發生第三次IO,採用二分法查找到29,查詢結束,共進行三次IO。
真實情況是,3層的B+樹可以表示上百萬的數據,如果上百萬的數據查詢只需要三次IO,性能提高將是巨大的,如果沒有索引,每個數據項都要發生一次IO,那麼總共需要百萬次的IO,顯然成本是非常高的。
有兩點需要注意:
1、索引字段要儘量的小
我們知道IO次數取決於B+樹的高度h,假設當前數據表的數據爲N,每個磁盤的數據項的數量是m,則有h=log(m+1)N,當數據量N一定的情況下,m越大,h越小。
而 m=磁盤塊大小/數據項大小,磁盤塊的大小也就是一個數據頁的大小,是固定的。如果數據項佔據的空間越小,磁盤塊所能容納的數據項也就越多,那麼樹的高度也就越低。這就是爲什麼每個數據項(索引字段)要儘量的小。
2、索引的最左匹配原則(即從左往右匹配)
如查找(name,age,sex) 先匹配 name,再匹配 age ,最後匹配 sex,如果 name 沒有匹配上則無法確定下一步。如果age缺失,則下一步匹配sex。
每一個父節點元素都出現在子節點中,爲子節點的最大值或者最小值。
跟節點的最大元素即整個B+樹的最大元素,之後無論增加或者減少元素,始終保持最大元素在跟節點。
葉子節點包含所有的數據,從左至右由小到大形成有序鏈表。
B+樹的特徵:
- 有k個子樹的中間節點包含有一個k元素(B樹中是k-1個元素),每個元素不保存數據,所有的數據均保存在葉子節點上。
- 所有的葉子節點中包含了全部元素的信息及指向含這些元素記錄的指針,且葉子節點本身以關鍵字的大小自小到大順序連接。
- 所有的中間節點元素都同時存在與子節點中,在子節點元素中爲最大值或者最小值。
B+樹的優勢:
- 單一節點存儲更多的元素,使得查詢的IO次數更少。
- 所有查詢都要查找葉子節點,查詢性能穩定。
- 所有葉子節點形成有序鏈表,便於範圍查詢。