MySQL之索引樹實現

2021-10-25 06:30:28 字數 3954 閱讀 6863

本文章**於: ,請star 強力支援,你的支援,就是我的動力。

[toc]

為什麼mysql的innodb中的索引要使用b+樹,而不是其它樹?比如b樹?

innodb的一棵b+樹可以存放多少行資料?

答案:約2千萬

怎麼計算出來的?先從innodb索引資料結構、資料組織、索引實現方式說起。

計算機在儲存資料的時候,有最小儲存單元,這就好比現金的流通最小單位是一毛。

在計算機中,磁碟儲存資料最小單元是扇區,乙個扇區的大小是512位元組,而檔案系統(例如xfs/ext4)的最小單元是塊,乙個塊的大小是4k,而對於innodb儲存引擎也有自己的最小儲存單元,頁(page),乙個頁的大小是16k。

檔案系統中乙個檔案大小只有1個位元組,但不得不佔磁碟上4kb的空間。

innodb的所有資料檔案(字尾為ibd的檔案),大小始終都是16384(16k)的整數倍。

磁碟扇區、檔案系統、innodb儲存引擎都有各自的最小儲存單元。

innodb儲存單元16k --> 檔案系統4k --> 磁碟扇區512b 分別組成;

在mysql中,innodb頁的大小預設是16k,當然也可以通過引數設定:

mysql> show variables like 'innodb_page_size'
表中的資料都是儲存在頁中的,所以乙個頁中能儲存多少行資料呢?

innodb儲存引擎的最小儲存單元是頁,頁可以用於存放資料也可以用於存放鍵值+指標,在b+樹中葉子節點存放資料,非葉子節點存放鍵值+指標。

索引組織表通過非葉子節點的二分查詢法以及指標確定資料在哪個頁中,進而在去資料頁中查詢到需要的資料;

因為b樹不管葉子節點還是非葉子節點,都會儲存資料,這樣導致在非葉子節點中能儲存的指標數量變少(有些資料也稱為扇出)

指標少的情況下要儲存大量資料,只能增加樹的高度,導致io操作變多,查詢效能變低;

b樹分析

b樹,如上圖,它的特點是:

(1)不再是二叉搜尋,而是m叉搜尋;

(2)葉子節點,非葉子節點,都儲存資料;

(3)中序遍歷,可以獲得所有節點;

畫外音,實在不想介紹這個特性:非根節點包含的關鍵字個數j滿足,(┌m/2┐)-1 <= j <= m-1,節點**時要滿足這個條件。

b樹被作為實現索引的資料結構被創造出來,是因為它能夠完美的利用「區域性性原理」。

什麼是區域性性原理?

區域性性原理的邏輯是這樣的:

(1)記憶體讀寫塊,磁碟讀寫慢,而且慢很多;

(2)磁碟預讀:磁碟讀寫並不是按需讀取,而是按頁預讀,一次會讀一頁的資料,每次載入更多的資料,如果未來要讀取的資料就在這一頁中,可以避免未來的磁碟io,提高效率;

畫外音:通常,一頁資料是4k。

(3)區域性性原理:軟體設計要盡量遵循「資料讀取集中」與「使用到乙個資料,大概率會使用其附近的資料」,這樣磁碟預讀能充分提高磁碟io;

b樹為何適合做索引?

(1)由於是m分叉的,高度能夠大大降低;

(2)每個節點可以儲存j個記錄,如果將節點大小設定為頁大小,例如4k,能夠充分的利用預讀的特性,極大減少磁碟io;

b+樹分析

b+樹,如上圖,仍是m叉搜尋樹,在b樹的基礎上,做了一些改進

(1)非葉子節點不再儲存資料,資料只儲存在同一層的葉子節點上;

畫外音:b+樹中根到每乙個節點的路徑長度一樣,而b樹不是這樣。

(2)葉子之間,增加了鍊錶,獲取所有節點,不再需要中序遍歷;

這些改進讓b+樹比b樹有更優的特性:

(1)範圍查詢,定位min與max之後,中間葉子節點,就是結果集,不用中序回溯;

畫外音:範圍查詢在sql中用得很多,這是b+樹比b樹最大的優勢。

(2)葉子節點儲存實際記錄行,記錄行相對比較緊密的儲存,適合大資料量磁碟儲存;非葉子節點儲存記錄的pk,用於查詢加速,適合記憶體儲存;

(3)非葉子節點,不儲存實際記錄,而只儲存記錄的key的話,那麼在相同記憶體的情況下,b+樹能夠儲存更多索引;

最後,量化說下,為什麼m叉的b+樹比二叉搜尋樹的高度大大大大降低?

那麼現在需要計算出非葉子節點能存放多少指標?

(1)區域性性原理,將乙個節點的大小設為一頁,一頁4k,假設乙個key有8位元組,乙個節點可以儲存500個key,即j=500

(2)m叉樹,大概m/2<= j <=m,即可以差不多是1000叉樹

(3)那麼:

一層樹:1個節點,1*500個key,大小4k

二層樹:1000個節點,1000500=50w個key,大小10004k=4m

三層樹:10001000個節點,10001000500=5億個key,大小10001000*4k=4g

畫外音:額,幫忙看下有沒有算錯。

可以看到,儲存大量的資料(5億),並不需要太高樹的深度(高度3),索引也不是太佔記憶體(4g)。

雜湊索引

對於innodb的雜湊索引,確切的應該這麼說:

(1)innodb使用者無法手動建立雜湊索引,這一層上說,innodb確實不支援雜湊索引;

(2)innodb會自調優(self-tuning),如果判定建立自適應雜湊索引(adaptive hash index, ahi),能夠提公升查詢效率,innodb自己會建立相關雜湊索引,這一層上說,innodb又是支援雜湊索引的;

那什麼是自適應雜湊索引(adaptive hash index, ahi)呢?原理又是怎樣的呢?

不妨設有innodb資料表:

t(id pk, name key, ***, flag)

*畫外音:*id是主鍵,name建了普通索引。

在主鍵id上會建立聚集索引(clustered index),葉子儲存記錄本身,在name上會建立普通索引(secondary index),葉子儲存主鍵值。

發起主鍵id查詢時,能夠通過聚集索引(主鍵id如上圖b+樹的節點數字),直接定位到行記錄。

發起普通索引查詢時:

(1)會先從普通索引查詢出主鍵;

(2)再由主鍵,從聚集索引上二次遍歷定位到記錄。

不管聚集索引還是普通索引,記錄定位的尋路路徑(search path)都很長。

在mysql執行的過程中,如果innodb發現,有很多sql存在這類很長的尋路,並且有很多sql會命中相同的頁面(page),innodb會在自己的記憶體緩衝區(buffer)裡,開闢一塊區域,建立自適應雜湊所有ahi,以加速查詢。

從這個層面上來說,innodb的自使用雜湊索引,更像「索引的索引」,畢竟其目的是為了加速索引尋路。

既然是雜湊,key是什麼,value是什麼?

key是索引鍵值(或者鍵值字首)。

value是索引記錄頁面位置。

為啥叫「自適應(adaptive)」雜湊索引?

系統自己判斷「應該可以加速查詢」而建立的,不需要使用者手動建立,故稱「自適應」。

系統會不會判斷失誤,是不是一定能加速?

不是一定能加速,有時候會誤判。

當業務場景為下面幾種情況時:

ahi往往是有效的。 畫外音:任何脫離業務的技術方案,都是耍流氓。

當業務有大量like或者join,ahi的維護反而可能成為負擔,降低系統效率,此時可以手動關閉ahi功能。

(1)很適合磁碟儲存,能夠充分利用區域性性原理,磁碟預讀;

(2)很低的樹高度,能夠儲存大量資料;

(3)索引本身占用的記憶體很小;

(4)能夠很好的支援單點查詢,範圍查詢,有序性查詢;

MySQL索引之B 樹索引

b 樹索引是是目前關係型資料庫系統中查詢最為常用和最為有效的索引,b 樹的索引構造類似於二叉樹,根據鍵值 key value 快速找到資料。1 什麼是b 樹?首先,b 樹中的b並不是二叉樹 binary 的意思,這裡的b表示的是blance即平衡的意思。那麼b 樹其實就是平衡查詢樹。其滿足兩個條件 ...

MySql索引之B 樹

使用何種資料結構作為索引底層實現的乙個重要衡量指標就是磁碟io的操作次數。對於資料庫而言,索引本身也很大,需要以索引檔案的形式儲存在磁碟上,因此磁碟io操作次數直接決定了索引的效能。b 樹能夠有效利用系統對磁碟的塊讀取特性,在讀取相同磁碟塊的同時,盡可能多的載入索引資料,來提高索引命中效率,從而達到...

Mysql之B樹索引

聚集索引 簡單概念 乙個表中根據主鍵建立的一棵b 樹,索引的葉子節點存放了表中所有的記錄,儲存記錄在物理位置上是連續的,乙個葉子節點存放一條對應的記錄 ps 是根據主鍵建立的b 樹,葉子節點存資料記錄 舉個例子 以漢語字典為例 漢語字典的正文本身就是乙個聚集索引,比如我們要查 安 字,由於漢語詞典的...