MySQL和B樹的那些事

2021-09-07 11:28:34 字數 4349 閱讀 4488

一、零鋪墊

在介紹b樹之前,先來看另一棵神奇的樹——二叉排序樹(binary sort tree),首先它是一棵樹,「二叉」這個描述已經很明顯了,就是樹上的一根樹枝開兩個叉,於是遞迴下來就是二叉樹了(下圖所示),而這棵樹上的節點是已經排好序的,具體的排序規則如下:

從圖中可以看出,二叉排序樹組織資料時,用於查詢是比較方便的,因為每次經過一次節點時,最多可以減少一半的可能,不過極端情況會出現所有節點都位於同一側,直觀上看就是一條直線,那麼這種查詢的效率就比較低了,因此需要對二叉樹左右子樹的高度進行平衡化處理,於是就有了平衡二叉樹(balenced binary tree)。

所謂「平衡」,說的是這棵樹的各個分支的高度是均勻的,它的左子樹和右子樹的高度之差絕對值小於1,這樣就不會出現一條支路特別長的情況。於是,在這樣的平衡樹中進行查詢時,總共比較節點的次數不超過樹的高度,這就確保了查詢的效率(時間複雜度為o(logn))。

二、b樹的起源

b樹,最早是由德國計算機科學家rudolf bayer等人於2023年在** 《organization and maintenance of large ordered indexes》提出的,不過我去看了看原文,發現作者也沒有解釋為什麼就叫b-trees了,所以把b樹的b,簡單地解釋為balanced或者binary都不是特別嚴謹,也許作者就是取其名字bayer的首字母命名的也說不定啊……

三、b樹長啥樣

還是直接看圖比較清楚,圖中所示,b樹事實上是一種平衡的多叉查詢樹,也就是說最多可以開m個叉(m>=2),我們稱之為m階b樹,為了體現本部落格的良心之處,不同於其他地方都能看到2階b樹,這裡特意畫了一棵5階b樹 。

總的來說,m階b樹滿足以下條件:

b樹的查詢過程和二叉排序樹比較類似,從根節點依次比較每個結點,因為每個節點中的關鍵字和左右子樹都是有序的,所以只要比較節點中的關鍵字,或者沿著指標就能很快地找到指定的關鍵字,如果查詢失敗,則會返回葉子節點,即空指標。

例如查詢圖中字母表中的k

從根節點p開始,k的位置在p之前,進入左側指標

左子樹中,依次比較c、f、j、m,發現k在j和m之間

沿著j和m之間的指標,繼續訪問子樹,並依次進行比較,發現第乙個關鍵字k即為指定查詢的值

四、plus版——b+樹

作為b樹的加強版,b+樹與b樹的差異在於

b+樹的查詢過程,與b樹類似,只不過查詢時,如果在非葉子節點上的關鍵字等於給定值,並不終止,而是繼續沿著指標直到葉子節點位置。因此在b+樹,不管查詢成功與否,每次查詢都是走了一條從根到葉子節點的路徑。

五、mysql是如何使用b樹的

說明:事實上,在mysql資料庫中,諸多儲存引擎使用的是b+樹,即便其名字看上去是btree。

1、innodb的索引機制

先以innodb儲存引擎為例,說明innodb引擎是如何利用b+樹建立索引的。首先建立一張表:zodiac,並插入一些資料

create

table

`zodiac` (

`id`

int(11) not

null

auto_increment,

`name`

char(4) not

null,

primary

key(`id`),

key`index_name` (`name`)

); insert zodiac(id,name) values(1,'

鼠'); &

nbsp;

insert zodiac(id,name) values(2,'

牛'); &

nbsp;

insert zodiac(id,name) values(3,'

虎'); &

nbsp;

insert zodiac(id,name) values(4,'

兔'); &

nbsp;

insert zodiac(id,name) values(5,'

龍'); &

nbsp;

insert zodiac(id,name) values(6,'

蛇'); &

nbsp;

insert zodiac(id,name) values(7,'

馬'); &

nbsp;

insert zodiac(id,name) values(8,'

羊'); &

nbsp;

insert zodiac(id,name) values(9,'猴'

);insert zodiac(id,name) values(10,'

雞'); &

nbsp;

insert zodiac(id,name) values(11,'

狗'); &

nbsp;

insert zodiac(id,name) values(12,'

豬');

對於innodb來說,只有乙個資料檔案,這個資料檔案本身就是用b+樹形式組織b+樹每個節點的關鍵字就是表的主鍵,因此innodb的資料檔案本身就是主索引檔案,如下圖所示,主索引中的葉子頁(leaf page)包含了資料記錄,但非葉子節點只包含了主鍵,術語「聚簇」表示資料行和相鄰的鍵值緊湊地儲存在一起,因此這種索引被稱為聚簇索引,或聚集索引。

這種索引方式,可以提高資料訪問的速度,因為索引和資料是儲存在同一棵b樹之中,從聚簇索引中獲取資料通常比在非聚簇索引中要來得快。

所以可以說,innodb的資料檔案是依靠主鍵組織起來的,這也就是為什麼innodb引擎下建立的表,必須指定主鍵的原因,如果沒有顯式指定主鍵,innodb引擎仍然會對該表隱式地定義乙個主鍵作為聚簇索引。

同樣innodb的輔助索引,如下圖所示,假設這些字元是按照生肖的順序排列的(其實我也不知道具體怎麼實現,不要在意這些細節,就是舉個例子),其葉子節點中也包含了記錄的主鍵,因此innodb引擎在查詢輔助索引的時候會查詢兩次,首先通過輔助索引得到主鍵值,然後再查詢主索引,略微有點囉嗦。。。

2、myisam的索引機制

myisam引擎同樣也使用b+樹組織索引,如下圖所示,假設我們的資料不是按照之前的順序插入的,而是按照圖中的是順序插入表,可以看到myisam引擎下,b+樹葉子節點中包含的是資料記錄的位址(可以簡單理解為「行號」),而myisam的輔助索引在結構上和主索引沒有本質的區別,同樣其葉子節點也包含了資料記錄的位址,稍微不同的是輔助索引的關鍵字是允許重複。

六、簡單對比

1、innodb輔助索引的葉子節點儲存的不是位址,而是主鍵值,這樣的策略減少了當出現行移動或者資料頁**時輔助索引的維護工作,雖然使用主鍵值當作指標會讓輔助索引占用更多空間,但好處是,innodb在移動行時無需更新輔助索引中的主鍵值,而myisam需要調整其葉子節點中的位址。

2、innodb引擎下,資料記錄是儲存在b+樹的葉子節點(大小相當於磁碟上的頁)上,當插入新的資料時,如果主鍵的值是有序的,它會把每一條記錄都儲存在上一條記錄的後面,但是如果主鍵使用的是無序的數值,例如uuid,這樣在插入資料時innodb無法簡單地把新的資料插入到最後,而是需要為這條資料尋找合適的位置,這就額外增加了工作,這就是innodb引擎寫入效能要略差於myisam的原因之一。

innodb和myisam索引的抽象圖

MySQL的那些事

我原本是 android 開發,後來轉了專案經理,在專案開發的過程中發現一些跟 mysql 相關的東西,就想著記錄下來,以下均為個人看法,歡迎溝通交流。我們專案資料庫一直用的都是 mysql,剛上線根本沒加索引,也沒什麼感覺。可是隨著使用者量的暴增,發現很多查詢操作都很慢,我們一直去檢查程式的流程是...

線段樹的那些事

作為一名蒟蒻,竟然學會了線段樹,也是神奇。現在就來交流一下我對線段樹的一些認識 1.線段樹是一種資料結構,每個節點儲存乙個區間的資訊 2.可以用來優化dp 求區間最值等 3.遞迴求解,從根節點開始往下遞迴 4.用空間換時間 這是建樹函式,其中l,r表示構造的區間,lc,rc表示這個節點的左節點和右節...

MySql索引那些事

it技術之家 2019 04 03 16 32 16 概述一 什麼是索引 資料庫索引,是資料庫管理系統中乙個排序的資料結構,以協助快速查詢 更新資料庫表中資料。就像我們以前用的新華字典的目錄一樣,能幫助我們快速查詢到某乙個字。二 索引的分類 分類角度索引名稱 資料結構b 樹,hash索引,r tre...