1、何爲索引?數據庫
一、索引是幫助數據庫高效獲取數據的排好序的數據結構。數據結構
二、索引存儲在文件中。性能
三、索引建多了會影響增刪改效率。優化
(下面這張圖爲計算機組成原理內容,每查詢一次索引節點,都會進行一次磁盤IO讀取,即要尋道和旋轉)spa
2、MySQL索引結構爲何是B+樹?指針
MySQL 建索引可以使用的數據結構有B+樹和Hash兩種,可是Hash用得不多, 優勢是能夠快速定位到某一行,缺點是不能解決範圍查詢問題。blog
對於若是不須要使用範圍查詢、只須要精準查詢的場景,可使用Hash索引方法,好比查電話號碼。索引
再說說主流的索引方法B+樹,先說下爲何不用別的樹結構,再說爲何用B+樹。內存
一、爲何不用二叉樹?字符串
若是碰到下面這種單邊增加的極端狀況,查找節點4和順序查找沒區別。(這種特殊狀況的二叉樹等同於鏈表,時間複雜度爲O(n))
二、爲何不用紅黑樹?
紅黑樹是一顆平衡二叉樹,數據量大的時候,樹的深度也很深,若是樹的深度有20層,而查找的數據在葉子節點,就要進行20次IO操做,性能低。
三、爲何不用B樹?
B樹的特色:
其實B樹就是在橫向作了文章,一個節點能夠存儲更多數據(大節點包含不少小節點),這樣相對來講,深度就會變淺。
提問:橫向的節點怎麼查,好比說查找上圖中的節點77?
從磁盤中把大節點查找出來,把這個大節點加載進內存中,節點77其實是在內存中查找的,在內存中作的是隨機訪問,速度很快,跟磁盤的尋道和旋轉相比的話,基本能夠忽略不計。
提問:爲何不可讓B樹橫向的度無限增大,這樣不就深度爲1,查找不就更快了?(度的含義:節點的數據存儲個數)
原本是想經過一次IO操做把一個大節點加載進內存,若是一個大節點的數據量太大的話, 則內存和硬盤一次交互沒辦法交換那麼多數據,假設一次只能交換1頁(4k)的數據(有上限,也有多是幾十頁,和計算機硬件有關),意味着CPU去硬盤上作一次IO操做只能取1頁的數據,那麼當一個大節點的數據量太大時,仍要進行屢次IO操做。所以,度是有上限的,MySQL會根據計算機硬件自動進行度的優化,一個大節點一般爲1頁空間。
四、爲何使用B+樹?(B+樹是B樹的變種,索引作了冗餘,存了多份,可是不要緊,索引只佔很小空間,好比下圖中的15節點)
B+樹的特色:
提問:爲何說B+樹能夠增大度?
由於非葉子節點只存儲索引一個值,不存儲data(B樹會存儲data),而大節點大小是肯定的,所以節點就能夠存儲更多的數據,即度能夠變得更大。這樣既保證度能夠達到最大,又保證一個大節點經過一次IO操做能夠加載進內存。(非葉子節點度更大,深度更淺,只有非葉子節點才影響查找次數,葉子節點是最後一次查找,對總的查找次數是沒有影響的,所以把data所有移到了葉子節點)
提問:爲何葉子節點之間還須要用指針?(一個大節點的尾節點和下一個大節點的頭節點之間的指針鏈接)
方便範圍查詢。好比查找上圖中key>18,若是沒有指針會很是麻煩,必須從頭開始查找,若是有指針,則能夠直接遍歷key>18的葉子節點(鏈表)。
B+樹索引的性能分析:
3、MySQL底層是怎麼用B+樹來存儲數據的?
MySQL有兩種常見的存儲引擎:InnoDB(默認)、MyISAM(用得少,在MySQL8.0中被廢棄掉了),存儲引擎範圍是表級別的。
一、MyISAM索引實現(非彙集)
.frm是表結構文件,.MYD是數據文件(MyISAM Data),.MYI是索引文件(MyISAM Index)。
MyISAM主鍵索引查找流程:先經過.MYI文件找到對應索引的文件指針,再根據文件指針去.MYD文件中定位對應的那行數據。
MyISAM普通索引查找流程:和主鍵索引查找流程一致。
二、InnoDB索引實現(彙集)
.frm是表結構文件,.ibd是數據和索引文件(InnoDB Data)
InnoDB主鍵索引查找流程:經過.ibd文件找到對應的索引,索引的value即爲那行對應的完整數據。
InnoDB普通索引查找流程:經過.ibd文件找到對應的索引,索引的value即爲那行對應的主鍵的值,再根據主鍵值去主鍵索引樹中找到對應的行數據。
提問:彙集索引和非彙集索引的區別?
彙集索引:表中那行數據的索引和數據都合併在一塊兒了。
非彙集索引:表中那行數據的索引和數據是分開存儲的。
提問:爲何InnoDB表必須有主鍵?
由於整個數據文件自己就是按照B+樹組織的一個索引文件,因此必需要有主鍵(建InnoDB表時不指定主鍵,默認會從表字段中選一列做爲惟一主鍵,若是不存在這種字段,則後臺默認生成一個長整型主鍵字段,MyISAM能夠沒有)。
提問:爲何推薦使用整型的自增主鍵?
提升查詢性能。若是是使用UUID做爲主鍵,第一,UUID長度很長,會浪費存儲空間,第二,UUID是字符串類型,比較大小要查找ASCII碼錶,查找速度沒有整型int查找速度快,第三,UUID是隨機生成無序的字符串,當數據插入時,有很大可能會致使節點位置移動,還可能形成不少其餘節點位置移動,簡單來講就是位置打亂了; 若是使用整型的自增主鍵,新插入的數據都會連續的插入到磁盤的物理空間。
提問:爲何InnoDB普通索引結構葉子節點存儲的是主鍵值?(一致性和節省存儲空間)
若是普通索引的value也存數據,那麼當往有主鍵索引和普通索引的表中插入數據時,索引結構中key對應的value要存儲兩份數據,增長維護成本。
單值索引:只有一個索引,如(id),size=1
聯合索引:多個索引合起來做爲一個聯合索引,如(id,name),size>1(單值索引是聯合索引size=1的特例)
提問:聯合索引的底層數據結構長什麼樣?
先比較id,若是id相等,再比較name,若是name也相等,則再比較date。(索引最左前綴原理,後面索引優化隨筆會講解)