mysql索引為啥要選擇B+樹 (上)

譚某人發表於2019-03-09

不知道你有沒有這種感覺,那些所謂的資料結構和演算法,在日常開發工作中很少用到或者幾乎不曾用到,可能只是在每次換工作準備面試的時候才會撿起來學習學習。

那我希望今天這篇文章能讓你對資料結構的具體應用能有個初步的概念,就從我們每天都在用的 mysql 資料庫說起吧。

今天這個標題,嚴格來說其實是不正確的,我在前面的文章中有這麼解釋過:

首先,mysql 主要是由 server 層和儲存層兩部分構成的。server >層主要包括聯結器、查詢快取,分析器、優化器、執行器。儲存層主要是用來儲存和查詢 資料的,常用的儲存引擎有 InnoDB、MyISAM,MySQL 5.5.5版本後使用 InnoDB >作為預設儲存引擎。

這篇文章我們主要討論 mysql 的儲存層,不同的儲存引擎其底層的資料結構是不一樣的,我們這裡就以預設的 InnoDB 為例,所以嚴格來說應該是 InnoDB 為啥要選擇 B+ 樹這種資料結構來儲存資料。

在文章正式開始之前,你先要知道 mysql 中的 InnoDB 在底層是採用 B+ 樹這種資料結構來儲存資料的。你先記住就好了,下面我們再來一步一步解釋為什麼。

  • 幾種常見的資料結構

首先你要知道,mysql 的索引主要是為了提高查詢效率的,那一定得找一個合適的資料結構來儲存資料,雜湊表、陣列、二叉搜尋樹這三種常見的資料結構都可以提高查詢效率。

  • 雜湊表

雜湊表就是一種以鍵值對來儲存資料的結構,你可以通過一個 key 就可以很快的查詢出對用的 value 值。雜湊表主要是利用了陣列的隨機訪問特性,實現思想主要是通過一個雜湊函式把 key 轉換成一個雜湊值,這個雜湊值就對應陣列中的某個下標。

但是由於雜湊表是無序的,區間查詢效率會非常的慢,所以雜湊表通常只用於查詢單個值。

  • 有序陣列

陣列就好說了,陣列具有連續性和隨機訪問特性,因此陣列都能很高效的進行單個等值查詢和區間查詢,但是 mysql 不僅僅是查詢資料,還會有插入和刪除資料的操作。

在有序陣列中插入或刪除一個資料會需要批量移動陣列中其他資料,這是一個不小的消耗,影響效能。因此有序陣列適合處理靜態資料,比如一些過往的不會再修改的資料。

在這裡你可能會問,既然雜湊表其實也是利用了陣列的特性,那有了陣列為啥還需要雜湊表呢。是因為陣列下標 key 只能是數字,而雜湊表可以支援字串 key,雜湊函式可以把這個 key 轉換成一個陣列下標。

同時,不同的 key 如果通過雜湊函式轉換成了相同的陣列下標,這就會造成衝突,在雜湊表中一般會通過再拉出一個連結串列來儲存這個衝突的值。

關於雜湊表這裡就不再多說了,後面的文章再詳細解釋雜湊表的原理以及相關應用。

  • 二叉搜尋樹

注意,二叉搜尋樹和二叉樹不一樣,二叉樹是指每個節點的左兒子小於父節點,父節點又小於右兒子,即二叉搜尋樹的中序遍歷就是一個有序序列。

由於索引不僅僅是存在記憶體中,還會儲存在硬碟中,因此就會涉及到 IO 效能了,就要求樹的高度不能太高。實際上 B+ 樹就是通過二叉搜尋樹推演改進的,我將在後面的文章再詳細解釋這個改進過程。

  • 小結

雜湊表適合等值查詢,由於是無序的,區間查詢會很慢。

有序陣列適合等值和區間查詢,但是陣列具有連續性,插入和刪除操作都可能需要移動其他元素。

二叉搜尋樹由於樹的高度,區間查詢需要中序遍歷,都會導致查詢效率很慢。

注意,在一些文章中經常會把 B+ 樹說成 B 樹或者 B-tree,這其實是錯誤的,B 樹和 B+ 是兩種不同的樹,B+ 樹是 B 樹的一個優化,後面的文章我會再詳細解釋這個優化過程。

而且 B- 樹其實也就是 B 樹,這個符號並不是加減中的減號,並不是所謂的 "B 減樹",只是一個連線符號而已。

這篇文章就先寫到這了,希望你能有些收穫,如果對你有一點點幫助,就給文章點個好看吧,感謝支援。

相關文章