索引本質上是一種數據結構,讓我們在查詢數據的時候盡量減少磁盤I/O。
前邊大概看了索引的原理。數據庫的復雜性,以及讀取磁盤時,磁盤I/O等。任何一種數據結構都不是憑空產生的,一定會有它的背景和使用場景,我們現在總結一下,我們需要這種數據結構能夠做些什么,其實很簡單,那就是:每次查找數據時把磁盤IO次數控制在一個很小的數量級,最好是常數數量級。
那么我們就想到如果一個高度可控的多路搜索樹是否能滿足需求呢?就這樣,b+樹應運而生
B+樹大概就是上邊這個玩意。
如上圖,是一顆b+樹,最上層是樹根,中間的是樹枝,最下面是葉子節點,關于b+樹后邊會看到,這里只說一些重點,淺藍色的塊我們稱之為一個磁盤塊或者叫做一個block塊,這是操作系統一次IO往內存中讀的內容,一個塊對應四個扇區,可以看到每個磁盤塊包含幾個數據項(深藍色所示,一個磁盤塊里面包含多少數據,一個深藍色的塊表示一個數據,其實不是數據,后面有解釋)和指針(黃色所示,看最上面一個,p1表示比上面深藍色的那個17小的數據的位置在哪,看它指針指向的左邊那個塊,里面的數據都比17小,p2指向的是比17大比35小的磁盤塊),如磁盤塊1包含數據項17和35,包含指針P1、P2、P3,P1表示小于17的磁盤塊,P2表示在17和35之間的磁盤塊,P3表示大于35的磁盤塊。
真實的數據存在于葉子節點即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指針,通過指針加載磁盤塊8到內存,發生第三次IO,同時內存中做二分查找找到29,結束查詢,總計三次IO。
真實的情況是,3層的b+樹可以表示上百萬的數據,如果上百萬的數據查找只需要三次IO,性能提高將是巨大的,如果沒有索引,每個數據項都要發生一次IO,那么總共需要百萬次的IO,顯然成本非常非常高。
b+樹性質
1.索引字段要盡量的小:
通過上面的分析,我們知道IO次數取決于b+數的高度h或者說層級,這個高度或者層級就是你每次查詢數據的IO次數,假設當前數據表的數據為N,每個磁盤塊的數據項的數量是m,則有h=㏒(m+1)N,當數據量N一定的情況下,m越大,h越小;
而m = 磁盤塊的大小 / 數據項的大小,磁盤塊的大小也就是一個數據頁的大小,是固定的,如果數據項占的空間越小,數據項的數量越多,樹的高度越低。
這就是為什么每個數據項,即索引字段要盡量的小,比如int占4字節,要比bigint8字節少一半。
這也是為什么b+樹要求把真實的數據放到葉子節點而不是內層節點,一旦放到內層節點,磁盤塊的數據項會大幅度下降,導致樹增高。當數據項等于1時將會退化成線性表。
2:索引的最左匹配特性:
簡單來說就是你的數據來了以后,從數據塊的左邊開始匹配,在匹配右邊的,知道這句話就行啦,我們繼續學下面的內容。當b+樹的數據項是復合的數據結構,比如(name,age,sex)的時候,b+數是按照從左到右的順序來建立搜索樹的,比如當(張三,20,F)這樣的數據來檢索的時候,b+樹會優先比較name來確定下一步的所搜方向,如果name相同再依次比較age和sex,最后得到檢索的數據;
但當(20,F)這樣的沒有name的數據來的時候,b+樹就不知道下一步該查哪個節點,因為建立搜索樹的時候name就是第一個比較因子,必須要先根據name來搜索才能知道下一步去哪里查詢。
比如當(張三,F)這樣的數據來檢索時,b+樹可以用name來指定搜索方向,但下一個字段age的缺失,所以只能把名字等于張三的數據都找到,然后再匹配性別是F的數據了, 這個是非常重要的性質,即索引的最左匹配特性。
B-Tree索引的特點
1、B-tree索引可以加快數據的查詢速度
存儲引擎不需要進行全表掃描來獲得需要的數據,取而代之的是從索引的根節點開始進行搜索。然后根據指針逐層向下查找,通過比較節點頁的值和有目標值就可以找到合適的指針進入下層節點,而這些指針實際上定義了子節點頁中值的上限和下限。
2、B-tree索引更適合進行范圍查詢
因為前面說過,B-tree對索引是順序組織存儲的,所以就很適合進行查找范圍數據。
B-tree索引的使用場景
1、 全值匹配的查詢
指的是和索引中的所有列進行匹配,比如查詢字段 name = ‘tom’;
2、匹配最左前綴的查詢
比如為a列和b列設置聯合索引,只要聯合索引的第一列(a列)符合查詢條件,索引就會被用到,若只是第二列(b列)符合條件則不會被用到該索引。
3、匹配列前綴的查詢
只匹配某一列的值的開頭部分
4、匹配范圍值
5、精準匹配某一列并范圍匹配另外一列
6、只訪問索引的查詢
在這里指的就是覆蓋索引,即只需要訪問索引,而無需訪問數據行
7、用于查詢中的order by 操作
索引樹中的節點是有序的。一般來說,若B-Tree可以按照某種方式查找到該值,那么也可以用這種方式用于排序。所以,如果 order by 子句中滿足前面列出的幾種查詢類型,則這個索引也可以滿足對應的排序需求。
B-Tree索引的限制
1、 若不是按照索引的最左列開始查找,則無法使用該索引
比如建立聯合索引(name 、phone_num),若搜索phone_num則無法使用該索引
2、使用索引時,不能跳過索引中的列
比如建立聯合索引(name 、phone_num 、addr),若搜索name和addr 則無法使用該索引只能使用那么過濾
3、not in 和 <> 操作無法使用該索引
4、若查詢中有某個列的范圍查詢,則其右邊的所有列都無法使用索引
注意:存儲引擎用不同的方式使用B-Tree索引,性能也各有不同,各有優劣。例如,MyISAM使用前綴壓縮的技術使得索引更小,但InnoDB則按照原數據格式進行存儲。
MyISAM索引通過數據的物理位置引用被索引的行,而InnoDB則根據逐漸引用被索引的行
以上大概簡單的了解了一下索引的B+樹數據結構。
有好的建議,請在下方輸入你的評論。
歡迎訪問個人博客
https://guanchao.site