享學特邀做者:老顧
相信小夥伴應該都用到過mysql數據庫,在mysql數據庫中,爲了提高查詢效率,都會使用到索引技術。今天老顧就來介紹一下mysql索引的數據結構的演變。mysql
咱們來看一下有個用戶表,存放這基本的用戶信息面試
需求要咱們找出id爲51的用戶信息算法
若是咱們是 mysql開發工程師的話,怎麼設計數據庫的查詢,最簡單作法就是一個個比較id,是否等於51,而後在返回給用戶。
這種方式會存在很大的問題:sql
一、運氣好的話 比較1次直接返回
二、運氣差的話 比較7次才能返回
這個方案就是所有遍歷的方式,從第一條記錄開始遍歷,一直遍歷下去。咱們這麼才7條記錄,若是幾百萬條,那查詢性能過低了。數據庫
爲了解決這個問題,咱們引入索引技術,改變一些數據存儲結構。首先想到的結構,就是二叉樹。數據結構
二叉樹的特色:
一、一個節點只能有兩個子節點,也就是一個節點度不能超過2
二、左子節點 小於 本節點;右子節點大於等於 本節點
咱們看一下上面的數據,以id爲索引,創建的二叉樹的結構是什麼?性能
由於二叉數的特色,右邊比左邊大,此次咱們查詢id=51,只須要比較3次,由於有一部分數據是不須要比較的,再索引創建的時候就已經排序好了。mysql索引
這個二叉樹比以前的遍歷的方案,性能提升了不少。但他也有一個問題, 若是id的值是持續遞增的話,會是什麼樣的結構?
咱們發現若是id是持續遞增的話,咱們的二叉樹結構出現了殘缺,若是這個時候查找id=5,也是從一直遍歷到最後,沒有像以前的數據那樣,排除掉一部分數據。那怎麼解決?優化
紅黑樹的出現就能夠解決這個問題,紅黑樹的特色會自動平衡樹,其餘特色(小夥伴們自行度娘)。咱們看一下紅黑樹怎麼平衡?設計
上面兩個圖,左圖在插入數值爲3時, 紅黑樹的算法發現有偏向,就會從新調整樹結構;調整到右邊的圖
那咱們能夠看看,以前的數據1~6持續遞增的樹,會變成什麼樣
咱們看到紅黑樹的結構,這樣咱們再次查找數據爲5,只須要比較3次,有部分數據被提早排序了。紅黑樹很好的平衡了樹的偏向問題,但紅黑樹問題也比較大。
一、每次都要檢查規則,再把樹進行從新平衡,這個是很是消耗時間的
二、數據量大的話,紅黑樹的深度會比較深,樹一旦深就表明着咱們讀取磁盤次數就會增長
小夥伴們有沒有發現,影響數據查詢時間的是樹的高度,高度越高,咱們須要比較的次數越多,那咱們是否是能夠想辦法把樹的高度弄低點?那咱們的B樹數據結構就由此產生。
B樹的特色
假如當前有一顆m階的B樹(注意階的意思是指每一個節點的孩子節點的個數),那麼其符合
(1) 每一個節點最多有m個子節點
(2)除了根節點和葉子節點以外,其餘的每一個節點最少有m/2(向上取整)個孩子節點
(3)根節點至少有兩個孩子節點,(除了第一次插入的時候,此時只有一個節點,根節點同時是葉子節點)
(4)全部的葉子節點都在同一層
(5)有k個子節點的父節點包含k-1個關鍵碼
(6)全部的葉節點都在同一層
(7) 每一個節點中的子節點都是從左到右排序的
小夥伴們是否是看到這個比較暈,這麼多的特色(其實還有更多性質,老顧也記不住);其實咱們不須要記住這麼多的特色,只要記住幾個核心點,先看圖
咱們的主要目標就是把樹的高度弄低,上圖中,咱們能夠看到以前的一個節點裏面多了幾個子節點(即幾階樹)【核心點一】,這樣的設計就是把以前節點只存儲1個數值,如今能夠存儲多個數值。
多個子節點數值都是從左到右排序【 核心點二】 ,有便於快速查找。並且 葉節點具備相同的深度,保證了每一個數值查詢效率一致【 核心點三】。
圖中每一個節點裏面都包含具體信息data【核心點四】,再查詢的時候找到對應的索引後,直接取出這個節點中的信息。
B樹的核心思想就是把樹高度弄低,用了樹節點包含多個子節點的設計思想,上圖中一個樹節點包含3個子節點。
小夥伴有沒有過這個想法,那咱們能夠把樹節點包含更多子節點,10個、100個、甚至1萬個,這樣就讓樹高度愈來愈小,甚至就只有一個樹根節點,這樣不是更好嗎?往下看
這裏就涉及到計算機原理的知識了,用通俗的圖表示一下
讀取數據流程主要交給磁頭和磁盤,咱們的數據存放在每一個扇區中,要讀取一個扇區數據,須要把磁頭移動到相應的磁道上面,而後磁盤快速旋轉,從而讀取到裏面值。(詳細知識自行度娘)
整個過程磁頭尋道是比較慢的,咱們與硬盤的交互儘可能減小尋道這個動做
上面小夥伴有個疑問,咱們可否擴大樹節點中的子節點數,甚至只有一個根節點就好了。這個是不行的,由於小夥伴們不要忘了, 內存也是有限的,全部數據存儲在一個根節點中,數據量一旦上億就吃不消了。
其實本質還有一個基本知識就是【磁盤有預讀機制,每次讀的時候都是加載一個磁盤頁到內存裏面】,這話的理解就是一次磁盤I/o讀取只能讀一個磁盤頁大小(4kb)的數據到內存中,也就是8kb的數據,要磁盤i/o的2次操做。
就是由於這個磁盤預讀機制,也就是不可能樹的節點隨便咱們設置,應該樹節點的數據量正好是一個磁盤頁的大小,這樣效率最高,一次IO讀取一個樹節點。
有了上面的知識鋪墊,終於到了這裏。咱們來看一下上面的B樹,一個樹節點咱們應該儘量的包含更多的子節點,但又不能超過一個磁盤頁(4kb)的大小。
咱們小夥伴們是否是想到進一步的優化點,咱們發現B樹的節點中還包含了一些關鍵字信息data,這個data也佔據着必定的數據量,咱們是否是能夠把data去掉,這樣就又能多加幾個子節點了。這也就是B+樹的核心思想,看圖
圖中能夠看出全部data信息都移動了子節點中,並且子節點和子節點之間會有個指針指向,這個也是B+樹的核心點,這樣能夠大大提高範圍查詢效率,也方便遍歷整個樹。
這樣的設計又大大的減小了樹的高度, 通常B+樹的階數(樹節點包含的子節點數)不會超過100,這樣通常保證樹的高度在3~5層而已,查詢速度大大的提高。
到了這裏應該知道爲何Mysql的索引結構採用了B+樹了吧,算法和數據結構一直在演變中。老顧這裏再留一個面試題,爲何InnoDB表必須有主鍵,而且推薦使用整型的自增主鍵,爲何不推薦用UUID?小夥伴結合上面知識想一想,謝謝!