首先要明白幾個概念,伺服器儲存一般分記憶體和硬碟,記憶體的大小相對於硬碟來說是很小的。記憶體的訪問速度是納秒級別的,非常快,而硬碟的訪問速度相對記憶體來說就比較慢了。
不管是訪問記憶體還是硬碟資料,作業系統都是按資料頁來讀取資料的,即每訪問一次硬碟或記憶體,只讀取一頁大小的資料,一頁的大小約等於 4 kb,向硬碟讀取資料的操作叫做磁碟 io。
看到這裡你或許會知道了 mysql 索引為啥不儲存在記憶體中了吧,一方面是雖然記憶體訪問速度快但容量一般都比較小,存不了多少資料,再乙個 mysql 需要讓資料持久化,如果伺服器斷電或異常重啟會導致資料丟失。
上篇文章中提到過二叉搜尋樹,為了讓二叉搜尋樹也支援區間查詢,我們把二叉樹的葉子節點通過乙個雙向鍊錶來連線,並且這個鍊錶是有序的,注意葉子節點和普通節點是不一樣的,注意看下面的圖。
因此只需要先找到區間的起始值在鍊錶中的位置,然後再往後遍歷,直到遍歷到區間的終止值,即可完成區間查詢。如下圖查詢 7-30 這個區間的資料。
因為二叉搜尋樹儲存在硬碟中,我們每訪問乙個節點,就對應著一次硬碟 io 操作,上面有說過向硬碟讀取資料速度比較慢。因此樹的高度就代表硬碟 io 操作的次數,所以我們要想辦法讓樹的高度變矮,來減少硬碟 io。
要想樹變矮一些,那就把樹多分一些叉來吧,變成一顆多叉樹。下面分別用二叉樹和五叉樹來儲存 16 條資料,看下樹的高度又怎樣的變化。
根節點一般儲存在記憶體中,普通節點和葉子結點儲存在硬碟中,因此顯然二叉樹的高度為 5,需要 5 次硬碟 io,而五叉樹的高度為 2,查詢乙個資料只需要 2 次硬碟 io。
當然這僅僅是乙個小資料的例子,如果有一億條資料,我們構建乙個 100 叉樹,這棵樹的高度也只有 3,因此多叉樹能大大降低硬碟 io,提公升查詢速度。
那麼問題又來了,對於相同的資料量,是不是構建的多叉樹的叉越多越好呢,因為叉越多樹的高度就會越矮。
上面有說過操作系是按資料頁大小來訪問硬碟的,每次 io 只讀取乙個資料頁大小的資料,如果要讀取的資料大於乙個資料頁,則會導致多次 io。因此我們要盡量讓每個節點的資料大小剛好等於乙個資料頁大小,即每訪問乙個節點只需一次 io。
上面講的其實都是為了提高查詢效能的,mysql 通常還有插入和刪除操作的,這裡我們再簡單說一下 b+ 樹如何處理插入和刪除節點的操作。
這裡我們把多叉樹稱作 m 叉樹,這個 m 值是通過資料頁大小和節點數計算出來的,盡量保證每訪問乙個節點就是乙個資料頁的大小,而且每個節點最多只有 m 個子節點。
現在我們要往資料庫中插入新的資料,即要往 m 叉樹中插入新的節點,這可能就會導致某些節點的子節點個數大於 m,也就會導致該節點大小大於乙個資料頁,訪問該節點就需要多次 io。
為了解決這個問題,m 叉樹會把該節點**成兩個節點,然後改**操作又會導致其父節點的子節點數可能超過 m,我們再用同樣的方法**節點,一直影響到根節點。
刪除操作也是類似的思想,如果有頻繁的刪除節點,就會導致某些節點的子節點過少,就會浪費儲存空間並降低查詢效率。所以就要想辦法讓這些節點合併起來,合併的話就有可能會導致其子節點數超過 m,超過的話就再用上面的**方法**子節點。
關於節點**和合併操作就簡單說這些了,也不畫圖了,知道這個處理思想就好了。
下面再總結一下 b+ 樹:
b+ 樹就是一種多叉樹,是由二叉搜尋樹不斷演變過來的,為了滿足區間快速查詢,b+ 樹的葉子節點通過雙向鍊錶串聯起來。
這裡使用雙向鍊錶是為了支援順序和倒序查詢,雖然雙向鍊錶相對於單向鍊錶雖然會浪費一倍的指標空間,但是在硬碟中這點空間幾乎微乎其微,用這點空間換時間是一件很值得的事情。
b+ 樹的子節點數不超過 m 個,同時也不能少於 m/2 個,一旦超過就需要**,一旦少於就需要合併。
MySQL索引為什麼選擇B 樹而不是B樹
b類樹的特點,b類樹保證盡量多的在結點上儲存相關的資訊,同時保證層數盡量的少,查詢更快,磁碟的io操作也少一些。b 樹的io更少 b 樹的非葉子節點沒有指向關鍵字具體資訊的指標,只用作索引,因此b 樹的非葉子節點比b樹占用更少磁碟空間。當資料量大時,一次不能把整個索引全部載入到記憶體,只能逐個載入每...
Mysql InnoDB 為啥選擇B 樹索引 一
mysql資料庫中的常見索引有多種方式,例如hash索引,b 樹索引,b 樹索引,但是為啥mysql中預設是採用b 樹索引索引呢?下面對這三種索引學習總結一下。b 樹到底有啥優勢?b 樹有如下特點 所有鍵值分布在整顆樹中 任何乙個關鍵字出現且只出現在乙個結點中 搜尋有可能在非葉子結點結束 在關鍵字全...
MySQL為什麼選擇B 樹做索引
b tree的基本概念 所有的葉子節點的高度都是一樣,這個保證了每次查詢資料的時候都是穩定的查詢效率,不會因為運氣的影響 b tree中其實每個非葉子節點內的小節點內其實都是乙個二元組 key,data key其實就是下圖的那個25這種的,然後這個data其實對應的就是資料庫中id等於25這條完整的...