MySQL 索引底层数据结构实现
文章目錄
- 概述
- 討論范圍
- 查詢數據結構
- 查詢數據結構種類及其高性能查詢原理
 
- MySQL 索引的底層數據結構
- MySQL 索引的需求分析
- 選擇 MySQL 索引的底層數據結構
- B- 樹和 B+ 樹的對比
- MySQL 索引的底層數據結構揭秘
 
概述
MySQL 的索引是存儲引擎用于快速找到記錄的一種數據結構,是提升 SQL 執行效率的神器。
 在正確建立及使用索引的情況下,查詢性能將會有非常大的提升(從 O(N) 提升到 O(logN),幾乎接近于常數級別);但在索引建立不正確或者使用不正確的情況下,將會進行全表掃描(O(N)),查詢性能就比較低下了。
討論范圍
為了不給讀者帶來可能的理解上的偏差以及困擾,在這里首先說明,本文中討論的索引是 MySQL 中 InnoDB 存儲引擎所使用的索引。
查詢數據結構
為了方便大家理解 MySQL 索引的底層數據結構,以及索引為什么能夠提升查詢性能,首先從查詢數據結構開始講解。
 查詢數據結構,光從字面上可能不太好理解。但是基于實際含義的角度上來看,或許應該叫便于查詢的數據結構,又或者叫高性能的查詢數據結構比較貼切。
 即,查詢數據結構是一種能提升數據查詢效率的數據結構。
查詢數據結構種類及其高性能查詢原理
常見的查詢數據結構,有以下幾種:
- 有序數組:一個數組,數組中的元素已經全部有序。利用其有序的性質,使用二分查找可以獲得 O(logN) 時間復雜度的查詢效率
- 跳表:一個鏈表(單或雙向都可以),鏈表中的所有節點都有序,且在原有鏈表的基礎上增加了一級或多級索引。利用其有序+索引性質,使用二分查找可以獲得 O(logN) 時間復雜度的查詢效率
- 哈希表:一種維護了鍵和值的唯一映射關系的數據結構,其本質是將鍵通過哈希函數+解決哈希沖突的某種手段散列到數組中的一種方法。利用數組的隨機訪問能力,可以獲得在最好情況下 O(1) 查詢時間復雜度,最壞情況的時間復雜度取決于哈希函數與解決哈希沖突的方法有關。
- 二叉搜索樹:一種節點間有序的二叉樹(具體定義在這里就不展開講了)。利用其有序的性質,使用二分查找在最好情況下可以獲得 O(logN) 時間復雜度的查詢效率,最壞情況下為 O(N)
- 紅黑樹:一種自平衡的二叉搜索樹。利用其有序的性質,使用二分查找可以獲得 O(logN) 時間復雜度的查詢效率
- B- 樹:B- 樹,是一種自平衡的多叉搜索樹。利用其有序的性質,使用二分查找可以獲得 O(logN) 時間復雜度的查詢效率
- B+ 樹:B+ 樹,也是一種自平衡的多叉搜索樹。利用其有序的性質,使用二分查找可以獲得 O(logN) 時間復雜度的查詢效率
可以看出,上面的數據結構,除了哈希表外,其余的數據結構都是利用了有序這個性質,并結合二分查找方法,即可獲得較高的(O(N) 時間復雜度)查詢效率。
 唯一一個例外是二叉搜索樹在最壞情況下(在節點分布極其不均勻,幾乎退化成單向鏈表的情況下),會退化成線性搜索,其復雜度為 O(N),如下圖所示:
 
可以看到,這個二叉搜索樹,幾乎已經退化成了一條單向鏈表,所以其查詢時間復雜度將會是 O(N)。
 所以我們得出一個結論:想要提高查詢效率,最好利用一個數據有序,且能自平衡(或者不需要平衡操作)的數據結構,再結合二分查找方法,即可達到目標。
 在上面這個,最重要的一點就是數據必須有序,因為如果數據無序,那么二分查找也無用武之地。
MySQL 索引的底層數據結構
假設你是 MySQL 的 InnoDB 存儲引擎的開發人員,你會選擇哪種數據結構作為索引底層的數據結構呢?
MySQL 索引的需求分析
想要實現一個功能,首先得分析清楚這個功能的需求是什么。現在我們想要實現 MySQL 的索引,那么索引的功能需求是什么呢?
 總的來說 MySQL 的索引有以下幾個需求點:
選擇 MySQL 索引的底層數據結構
弄清楚需求后,我們使用排除法來篩選所有可用的查詢數據結構:
- 有序數組:不能滿足 3、4、5,排除。有序數組隨機插入和刪除元素的復雜度為 O(N),且有序數組在數據量較大時,將數據從磁盤讀入內存的 IO 次數將不可控
- 跳表:不能滿足 4、5,排除。跳表與有序數組相同,從磁盤讀入內存的每個數據頁取決于數據本身的大小;在數據量較大時,將數據從磁盤讀入內存的 IO 次數將不可控
- 哈希表:不能滿足 2,排除。哈希表不支持范圍查詢
- 二叉搜索樹:不能自平衡,排除
- 紅黑樹:不能滿足 4、5,排除。紅黑樹雖然能自平衡,但是在數據量較大的情況下,樹的高度將會非常大,將數據從磁盤讀入內存的 IO 次數也會非常多
- B- 樹:基本可以滿足所有條件
- B+ 樹:可以滿足所有條件
經過上面的比對,我們最終確定了 B- 樹和 B+ 樹兩種數據結構可以滿足我們的需求,那么這兩種數據結構哪種更適合用于實現 MySQL 的索引呢?
B- 樹和 B+ 樹的對比
B- 樹和 B+ 樹,兩者都屬于自平衡的多叉搜索樹。但是從細節上來說,兩者之間有如下的區別:
- B+ 樹只有在葉子節點上才會攜帶數據,而 B- 樹在每個節點上都會攜帶數據 - 這個特性決定了 B+ 樹在非葉子節點上存儲的關鍵字數量越多,那么樹的階就會越大,則樹中的節點就會越少,則樹的高度就會越低
- 樹的高度越高,則每次查詢的時候需要進行的磁盤 IO 操作就會越多
- 樹的階越大,即非葉子節點上存儲的關鍵字數量越多,則從磁盤讀入內存的每個數據頁所包含的信息數量就越多
 
- B+ 樹對于范圍查詢的性能更高 - B+ 樹的所有葉子節點組成了一個有序的鏈表,在進行范圍查詢時,只需要遍歷葉子節點組成的鏈表就行
- B- 樹在進行范圍查找時,需要反復地中序遍歷,才能獲得范圍內的所有數據
 
下面的圖說明了在存儲同一組數據時,B- 樹和 B+ 樹的區別:
 
 
 在這里,我們模擬 B- 樹因為所有節點都要存儲數據,所以階為 3 的情況;而 B+ 樹只有在葉子節點上才會存儲數據,所以階會比 B- 樹要大,這里設定為 4。
 可以看到,在存儲同一組數據時,B- 樹的高度比 B+ 樹要高;且 B+ 樹的所有葉子節點組成了一個有序鏈表,范圍查詢時更方便也更高效。
MySQL 索引的底層數據結構揭秘
根據上面的分析,我們可以得出,要實現 MySQL 索引,底層數據結構選擇 B+ 樹最為合適。而實際上,MySQL 的 InnoDB 存儲引擎也確實是使用 B+ 樹作為底層的數據結構的。
 而 InnoDB 除了實現標準的 B+ 樹功能外,還有以下的實現細節值得關注:
- InnoDB 數據頁的大小(由參數 innodb_page_size 決定)決定了 B+ 樹的節點的大小,也決定了這個節點上存儲的關鍵字數量 - 默認的一個頁的大小為 16KB,高度為 3 的 B+ 樹即可存儲千萬級別的數據量
 
- 葉子節點組成的鏈表為雙向鏈表,可以更方便也是更高效地處理范圍查詢
總結
以上是生活随笔為你收集整理的MySQL 索引底层数据结构实现的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: Java Lambda 表达式讲解
- 下一篇: php按每小时显示数据,mysql-PH
