你必定能看懂的mysql索引

寫在前面

面試官:請你描述一下mysql中索引。
我:哦。。索引大概相似字典中的目錄,使用索引可以加快咱們的查詢效率。
面試官:還有呢?
我:沒了。
面試官:回去等通知。
我:好的。。html

你只看到了索引的第二層,你覺得它在第一層,實際上它是第五層——LOL金牌講師大司馬千層博弈論java

本片文章將從底層數據結構到應用帶你瞭解索引,讓你知其然還知其因此然mysql

索引結構

從表象上看

在咱們建立索引的時候,mysql爲咱們提供了 兩種索引結構

  • HASH
  • BTREE

HASH

類比一下咱們javaHashMap不難理解:
key-value的形式檢索數據,根據索引值生成hashCode,指向具體的行數據面試


特色:

  • 等值查詢很是快,效率爲O(1)
  • 數據是無序存儲的,因此沒法支持範圍查詢
  • 重複的hash值不少時,會形成大量的hash衝突,造成鏈表(鏈表越長,查詢效率越低,因此在jdk1.8的HashMap中將過長的鏈表轉換爲了紅黑樹)

BTREE

這是咱們應用最普遍的索引結構,咱們通常稱爲B+樹,爲何稱它爲B+樹呢,咱們來詳細分析一下各類數據結構。sql

查找二叉樹(Binary Search Tree)

在線模擬:www.cs.usfca.edu/~galles/vis…數據結構

咱們亂序的插入一些數據
6 3 5 7 8 13 9分佈式

  • 特色:左子節點 < 根節點 < 右子節點
  • 可以實現快速查找和插入,查找的耗時跟數據所在節點的深度有關

可是在極端狀況下(按大小順序插入),可能演變成鏈表post

這樣查找一些比較深的數據時,近乎就是 遍歷整個樹了

平衡二叉樹(AVL Tree)

在線模擬:www.cs.usfca.edu/~galles/vis…3d

特色:

  • 會經過旋轉來保證:左右子樹深度差絕對值不能超過 1

假如咱們採用這種數據結構,咱們能夠猜測:
在每個節點上會存放:指針

  • 1.索引的值
  • 2.索引對應行數據的地址
  • 3.左右子節點的引用

這裏穿插一個的概念: 咱們知道InnoDB(這裏不對其餘不經常使用引擎展開討論)中的數據都是存儲在磁盤上的,而咱們對數據進行讀寫時,必需要先將其加載到內存中,InnoDB採起的方式是:將數據劃分爲若干個頁,以頁做爲磁盤和內存之間交互的基本單位,InnoDB中頁的大小通常爲 16KB。

反觀咱們上文的結構:我查詢「3」這條數據須要進行3次查找(io消耗)

  • 每一次加載的數據很是少(每次加載一個節點裏的數據,浪費一次io,遠遠小於innodb中16K的頁)
  • 當數據量變多時,因爲只有兩個分叉,致使樹的高度會很高,查詢底部的數據時,io次數會很是多

多路平衡查找樹(B Tree)

在線模擬 www.cs.usfca.edu/~galles/vis…

經過分裂與合併來保證:分叉數(路數)永遠比關鍵字數多1
如圖度數爲3的B樹,每一個節點(頁)最多存儲2個關鍵字,最多擁有3個分叉。

  • 路數變多,樹由「高瘦」變得「矮胖」,查詢數據所需的io次數變少

假設:B 樹在枝節點和葉子節點存儲鍵值、數據地址、節點引用。
若是咱們B樹的路數有1000的話,一顆三層的B樹能夠存儲1000x1000x1000約10億條數據(在只計算葉子節點的狀況下),即只須要最多3次io就能夠查到近10億條的數據。

  • 這裏有個小問題:有些數據在根節點或者葉枝節點,而大部分數據存儲在葉子節點,致使每次查詢所需的io次數不一致(上層的根節點數據io次數少,下層的葉子節點所需io次數多)。

B+ 樹索引 (主角登場)

在線模擬 www.cs.usfca.edu/~galles/vis…

標準的B+樹:

在mysql中,B+索引對標準的B+樹作了一些改變:

特色:

  • 路數與關鍵字相等

每一個節點存儲更多關鍵字

  • 根節點和枝節點中都不會存儲數據(只保存頁號與對應頁中最小的索引值),只有葉子節點才存儲數據

保證每次查詢io(次數/耗時/效率)一致
根節點,枝節點不保存完整數據,能保存更多的關鍵字

  • 每一個葉子節點保存了一個指向相鄰葉子節點的指針,造成了一個有序鏈表的結構。

範圍查詢更快,全表遍歷更快,只須要遍歷葉子節點,不用遍歷整棵樹

索引類型

聚簇索引(主鍵索引)

B+樹的葉子節點存儲的是完整的行記錄

由於是完整的記錄因此叫聚簇麼。。

二級索引(非主鍵索引)

也是由索引建值構成的B+樹,只不過葉子節點只保存了索引建值與主鍵值

舉個栗子:以c列建立的二級索引
在查詢條件只包含c時,只過一遍c列構成的B+樹便可
查詢條件包含c列之外的字段時,須要經過c列的B+樹拿到主鍵值,在走一遍主鍵的B+樹,這個過程也叫回表。

聯合索引(主鍵索引)

以(a,b,c)三列建立的聯合索引,會先根據a排序,若a相等再根據b排序,若a,b相等再根據c排序,來建立一顆B+樹

這也是最左匹配原則的由來:只有查詢條件裏包含(a)(a,b)(a,b,c)列纔會走索引,條件前後順序無所謂,由於mysql會分析各類成本,來選擇最優的執行順序,即只要查詢條件符合索引的排序規則

使用索引的注意事項

  • 在用於where,order,join on的字段上創建索引

這個你們都懂,很少BB了

  • 在使用like關鍵字的時候,要使用「key%」後綴匹配(最左匹配原則)

咱們知道B+樹維護的是一個從小到大順序的集合。
對於字符串索引B+樹的排序規則:先根據第一個字符排序,若第一個字符相對再根據第二個字符排序。。以此類推。
只有使用「key%」才能根據「key」等值查找到知足條件最小的值,再經過鏈表向後遍歷。

  • 頻繁更新的值不要做爲索引或主鍵

內部維護了一個有序的B+樹,若改變其中的大小會致使B+樹中大量的頁分裂與合併,會形成很大的開銷

  • 主鍵最好使用int型的自增

理由同上,避免頻繁的頁分裂

  • 索引的個數不宜太多,能夠按照標識度來創建一個複合索引

咱們知道每個索引都會建立一顆B+樹,要排序,插入的效率會很是低

  • 區分度(離散度)低的字段(相似性別只有男女兩個值)上不要創建索引

區分度低,查詢效率低,還須要維護索引,回表屢次io,不如全表掃描

其餘文章推薦

相關文章
相關標籤/搜索