MySQL索引底層數據結構

1、何爲索引?數據庫

一、索引是幫助數據庫高效獲取數據的排好序數據結構數據結構

二、索引存儲在文件中。性能

三、索引建多了會影響增刪改效率。優化

(下面這張圖爲計算機組成原理內容,每查詢一次索引節點,都會進行一次磁盤IO讀取,即要尋道和旋轉)spa

2、MySQL索引結構爲何是B+樹?指針

MySQL 建索引可以使用的數據結構有B+樹Hash兩種,可是Hash用得不多, 優勢是能夠快速定位到某一行,缺點是不能解決範圍查詢問題。blog

對於若是不須要使用範圍查詢、只須要精準查詢的場景,可使用Hash索引方法,好比查電話號碼。索引

再說說主流的索引方法B+樹,先說下爲何不用別的樹結構,再說爲何用B+樹。內存

一、爲何不用二叉樹?字符串

若是碰到下面這種單邊增加的極端狀況,查找節點4和順序查找沒區別。(這種特殊狀況的二叉樹等同於鏈表,時間複雜度爲O(n))

二、爲何不用紅黑樹?

紅黑樹是一顆平衡二叉樹,數據量大的時候,樹的深度也很深,若是樹的深度有20層,而查找的數據在葉子節點,就要進行20次IO操做,性能低。

三、爲何不用B樹?

B樹的特色:

  • 葉子節點具備相同的深度
  • 葉子節點的指針爲空
  • 葉子節點中的數據key從左到右遞增排列

其實B樹就是在橫向作了文章,一個節點能夠存儲更多數據(大節點包含不少小節點),這樣相對來講,深度就會變淺。

提問:橫向的節點怎麼查,好比說查找上圖中的節點77?

從磁盤中把大節點查找出來,把這個大節點加載進內存中,節點77其實是在內存中查找的,在內存中作的是隨機訪問,速度很快,跟磁盤的尋道和旋轉相比的話,基本能夠忽略不計。

提問:爲何不可讓B樹橫向的度無限增大,這樣不就深度爲1,查找不就更快了?(度的含義:節點的數據存儲個數)

原本是想經過一次IO操做把一個大節點加載進內存,若是一個大節點的數據量太大的話, 則內存和硬盤一次交互沒辦法交換那麼多數據,假設一次只能交換1頁(4k)的數據(有上限,也有多是幾十頁,和計算機硬件有關),意味着CPU去硬盤上作一次IO操做只能取1頁的數據,那麼當一個大節點的數據量太大時,仍要進行屢次IO操做。所以,度是有上限的,MySQL會根據計算機硬件自動進行度的優化,一個大節點一般爲1頁空間。

四、爲何使用B+樹?(B+樹是B樹的變種,索引作了冗餘,存了多份,可是不要緊,索引只佔很小空間,好比下圖中的15節點)

B+樹的特色:

  • 非葉子節點不存儲data,只存儲key,能夠增大度(相比B樹,B+樹的深度更淺)
  • 葉子節點不存儲指針
  • 順序訪問指針,提升區間訪問的性能(其實是雙向指針)

提問:爲何說B+樹能夠增大度?

由於非葉子節點只存儲索引一個值,不存儲data(B樹會存儲data),而大節點大小是肯定的,所以節點就能夠存儲更多的數據,即度能夠變得更大。這樣既保證度能夠達到最大,又保證一個大節點經過一次IO操做能夠加載進內存。(非葉子節點度更大,深度更淺,只有非葉子節點才影響查找次數,葉子節點是最後一次查找,對總的查找次數是沒有影響的,所以把data所有移到了葉子節點)

提問:爲何葉子節點之間還須要用指針?(一個大節點的尾節點和下一個大節點的頭節點之間的指針鏈接)

方便範圍查詢。好比查找上圖中key>18,若是沒有指針會很是麻煩,必須從頭開始查找,若是有指針,則能夠直接遍歷key>18的葉子節點(鏈表)。 

B+樹索引的性能分析:

  • 通常使用磁盤I/O次數評價索引結構的優劣
  • 預讀:磁盤通常會順序向後讀取必定長度的數據(頁的整數倍)放入內存
  • 局部性原理:當一個數據被用到時,其附近的數據也一般會立馬被使用
  • B+樹的大節點大小設爲等於一個頁,每次新建大節點直接申請一個頁的空間,這能保證一個大節點物理上也存儲在一個頁裏,大節點載入只需一次IO操做
  • B+樹的度d通常會超過100,所以高度h很是小(通常爲3~5之間

3、MySQL底層是怎麼用B+樹來存儲數據的?

MySQL有兩種常見的存儲引擎:InnoDB(默認)、MyISAM(用得少,在MySQL8.0中被廢棄掉了),存儲引擎範圍是表級別的。

一、MyISAM索引實現(非彙集)

  • 索引文件和數據文件是分離的
  • 索引結構的葉子節點value存儲的是文件指針。

.frm是表結構文件,.MYD是數據文件(MyISAM Data),.MYI是索引文件(MyISAM Index)。

MyISAM主鍵索引查找流程:先經過.MYI文件找到對應索引的文件指針,再根據文件指針去.MYD文件中定位對應的那行數據。

MyISAM普通索引查找流程:和主鍵索引查找流程一致。

 二、InnoDB索引實現(彙集)

  • 數據文件自己就是索引文件
  • 表數據文件自己就是按B+樹組織的一個索引結構文件
  • 彙集索引的葉子節點包含了完整的數據記錄
  • 表必須有主鍵,且推薦使用整型的自增主鍵
  • 普通索引結構葉子節點存儲的是主鍵值

.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。(索引最左前綴原理,後面索引優化隨筆會講解)

相關文章
相關標籤/搜索