一、b+樹是什麼
b+ 樹是一種樹型資料結構,通常用於資料庫和作業系統的檔案系統中。b+ 樹的特點是能夠保持資料穩定有序,其插入與修改操作擁有較穩定的對數時間複雜度。b+ 樹元素自底向上插入,這與二叉樹恰好相反。
b+ 樹的創造者rudolf bayer沒有解釋b代表什麼。最常見的觀點是b代表平衡(balanced),因為所有的葉子節點在樹中都在相同的級別上。b也可能代表bayer,或者是波音(boeing),因為他曾經工作於波音科學研究實驗室
1)b+樹的節點
在 b+ 樹中的節點通常被表示為一組有序的元素和子指標。如果此b+樹的序數(order)是m ,則除了根之外的每個節點都包含最少 [m/2] 個元素最多 [m-1] 個元素,對於任意的節點有最多 m 個子指標。對於所有內部節點,子指標的數目總是比元素的數目多乙個.
2)b+樹相應的操作
1.查詢
2.插入
3.刪除
3)b+樹的特點
1.每個節點中子節點的個數不能超過 m,也不能小於 m/2;
2.根節點的子節點個數可以不超過 m/2,這是乙個例外;
3.m 叉樹只儲存索引,並不真正儲存資料,這個有點兒類似跳表;
4.通過鍊錶將葉子節點串聯在一起,這樣可以方便按區間查詢;
5.一般情況,根節點會被儲存在記憶體中,其他節點儲存在磁碟中
4)在這裡說下b 樹、b- 樹
b- 樹就是 b 樹,英文翻譯都是 b-tree,這裡的「-」並不是相對 b+ 樹中的「+」,而只是乙個連線符。
而 b 樹實際上是低階版的 b+ 樹,或者說 b+ 樹是 b 樹的改進版。b 樹跟 b+ 樹的不同點主要集中在這幾個地方:
b+ 樹中的節點不儲存資料,只是索引,而 b 樹中的節點儲存資料;
b 樹中的葉子節點並不需要鍊錶來串聯。
也就是說,b 樹只是乙個每個節點的子節點個數不能小於 m/2 的 m 叉樹
b-tree:
b+tree:
二、mysql資料庫索引為啥使用b+樹作為底層資料結構
1)明確資料庫索引是解決什麼問題的
這裡舉最常用的兩個功能性需求:
1.根據某個值查詢資料,比如 select * from user where id=1234;
2.根據區間值來查詢某些資料,比如 select * from user where id > 1234 and id < 2345;
然後是非功能性需求比如效能方面的:
主要考察時間和空間兩方面,也就是執行效率和儲存空間。
在執行效率方面,我們希望通過索引,查詢資料的效率盡可能的高;在儲存空間方面,我們希望索引不要消耗太多的記憶體空間。
2)明確了待解決的問題,然後就是用已知的資料結構解決問題
我們已知的支援快速查詢、插入等操作的動態資料結構有:雜湊表、平衡二叉查詢樹、跳表、b+樹
1.雜湊表 (不滿足)
雜湊表的查詢效能很好,時間複雜度是 o(1)。但是,雜湊表不能支援按照區間快速查詢資料
2.平衡二叉查詢樹(不滿足)
平衡二叉查詢樹查詢的效能也很高,時間複雜度是 o(logn)。而且,對樹進行中序遍歷,我們還可以得到乙個從小到大有序的資料序列,但這仍然不足以支援按照區間快速查詢資料
3.跳表(滿足)
跳表是在鍊錶之上加上多層索引構成的。它支援快速地插入、查詢、刪除資料,對應的時間複雜度是 o(logn)。並且,跳表也支援按照區間快速地查詢資料。我們只需要定位到區間起點值對應在鍊錶中的結點,然後從這個結點開始,順序遍歷鍊錶,直到區間終點對應的結點為止,這期間遍歷得到的資料就是滿足區間值的資料。
4.b+樹 (滿足)
b+樹這種資料結構跟跳表非常相似,所以適合做資料庫索引。不過,它是通過二叉查詢樹演化過來的,而非跳表。
3)確定使用b+樹後,那麼如何解決索引占用太多記憶體的問題呢?
因為作為資料庫索引,儲存的資料可能非常的大,比如給一億個資料構建索引,那索引中會包含大約 1 億個節點,每個節點假設占用 16 個位元組,那就需要大約 1gb 的記憶體空間。給一張表建立索引,我們需要 1gb 的記憶體空間。如果我們要給 10 張表建立索引,那對記憶體的需求是無法滿足的。
那麼我們就需要借助空間換時間的思路,把索引儲存在硬碟中,而非記憶體中。我們都知道,硬碟是乙個非常慢速的儲存裝置。通常記憶體的訪問速度是納秒級別的,而磁碟訪問的速度是毫秒級別的。讀取同樣大小的資料,從磁碟中讀取花費的時間,是從記憶體中讀取所花費時間的上萬倍,甚至幾十萬倍。
將索引儲存在硬碟中後,儘管減少了記憶體消耗,但是在資料查詢的過程中,需要讀取磁碟中的索引,因此資料查詢效率就相應降低很多。對於b+樹來說,每個節點的讀取(或者訪問),都對應一次磁碟 io 操作。樹的高度就等於每次查詢資料時磁碟 io 操作的次數。我們優化的重點就是儘量減少磁碟 io 操作,也就是,盡量降低樹的高度。
4)為了提高b+樹索引的效率,那麼如何降低樹的高度?
對於b+樹來說,其實可以看做是 m 叉樹,那麼樹的高度就取決於 m 的大小。比如給 16 個資料構建二叉樹索引,樹的高度是 4,查詢乙個資料,就需要 4 個磁碟 io 操作(如果根節點儲存在記憶體中,其他結點儲存在磁碟中),如果對 16 個資料構建五叉樹索引,那高度只有 2,查詢乙個資料,對應只需要 2 次磁碟操作。如果 m 叉樹中的 m 是 100,那對一億個資料構建索引,樹的高度也只是 3,最多只要 3 次磁碟 io 就能獲取到資料。磁碟 io 變少了,查詢資料的效率也就提高了。
m越大,樹的高度就越小,那麼m是不是越大越好呢?不是,不管是記憶體中的資料,還是磁碟中的資料,作業系統都是按頁(一頁大小通常是 4kb,這個值可以通過 getconfig page_size 命令檢視)來讀取的,一次會讀一頁的資料。如果要讀取的資料量超過一頁的大小,就會觸發多次 io 操作。所以,我們在選擇 m 大小的時候,要盡量讓每個節點的大小等於乙個頁的大小。讀取乙個節點,只需要一次磁碟 io 操作。
5)索引的使用也會導致寫入資料效率的下降
儘管索引可以提高資料庫的查詢效率,但是,作為一名開發工程師,你應該也知道,索引有利也有弊,它也會讓寫入資料的效率下降
/*** 這是 b+ 樹非葉子節點的定義。
* 假設 keywords=[3, 5, 8, 10]
* 4 個鍵值將資料分為 5 個區間:(-inf,3), [3,5), [5,8), [8,10), [10,inf)
* 5 個區間分別對應:children[0]...children[4]
* m 值是事先計算得到的,計算的依據是讓所有資訊的大小正好等於頁的大小:
* page_size = (m-1)*4[keywordss 大小]+m*8[children 大小]*/
public classbplustreenode /*** 這是 b+ 樹中葉子節點的定義。
* b+ 樹中的葉子節點跟內部結點是不一樣的,
* 葉子節點儲存的是值,而非區間。
* 這個定義裡,每個葉子節點儲存 3 個資料行的鍵值及位址資訊。
* k 值是事先計算得到的,計算的依據是讓所有資訊的大小正好等於頁的大小:
* page_size = k*4[keyw.. 大小]+k*8[dataad.. 大小]+8[prev 大小]+8[next 大小]*/
public classbplustreeleafnode {public static int k = 3;public int keywords = new int[k]; //資料的鍵值
public long dataaddress = new long[k]; //資料位址
public bplustreeleafnode prev; //這個結點在鍊錶中的前驅結點
public bplustreeleafnode next; //這個結點在鍊錶中的後繼結點
MySQL資料庫基礎 MySQL資料庫與資料表操作
資料表操作 3.修改表名 4.更改表的自增的值 5.修改表引擎 6.刪除表 資料表的操作 資料庫操作 1.資料庫的建立 鏈結mysql資料庫後,進入demo後可以運算元據 1.建立庫 create database if not exists demo default charset utf8 1....
Mysql資料庫B 樹
一般來說,索引檔案占用空間比較大,需要儲存在磁碟上。索引查詢需要通過磁碟i o操作才能進行,而我們知道,磁碟i o比記憶體讀取要高幾個數量級,所以如何減少磁碟i o次數,是索引資料結構選擇的首要參考條件。計算機區域性性原理認為 當乙個資料被用到時,其附近的資料也通常會馬上被使用。因此為了減少磁碟i ...
mysql資料庫載入太慢 使用MySQL資料庫很慢
對於2000資料庫,您應該調整table cache設定.您肯定在此快取中有很多快取未命中.嘗試使用mysqltunner和 或tunning primer.sh獲取有關設定潛在問題的其他資訊.現在drupal使資料庫工作量很大,請檢查一下drupal的安裝,您可能會生成很多 太多 的請求.關於in...