1. 程式人生 > >mysql那些事之索引篇

mysql那些事之索引篇

### mysql那些事之索引篇 上一篇部落格已經簡單從廣的方面介紹了一下mysql整體架構以及物理結構的內容. 本篇部落格的內容是mysql的索引,索引無論是在面試還是我們日常工作中都是非常的重要一環. #### 索引是什麼? - 官方介紹索引是幫助MySQL高效獲取資料的資料結構.打個比方來說的話相當於我們生活中字典. #### 索引的優勢和劣勢 - 優勢: - 可以加快資料的檢索速度,降低磁碟的IO,提高查詢效率. - 索引列可以對資料進行排序,減低cpu的消耗 - 劣勢: - 索引是需要佔用磁碟空間的. - 索引只是針對查詢會提升效能.對增刪改反而會降低.原因是因為要維護索引,會產生磁碟IO. #### 索引的分類 - 單列索引 - 普通索引:mysql中的基本索引型別,只是為了查詢快一些. - 主鍵索引:mysql主鍵列上新增索引.不允許有null和空值 - 唯一索引:唯一列上新增索引,允許有null和空值 - 組合索引 - 在同一張表裡多個列上新增索引 - 需要遵循最左字首原則 - 建議使用組合索引替代單列索引,主鍵索引分情況. #### 索引的使用 ##### 索引的建立 首先說明我們有一張user表,欄位分別為主鍵id,name,age. - 單列普通索引 ``` sql create index idx_name on user(name(10)); ``` ​ 這裡想說明一下,我們在工作中對某個欄位新增索引時,目標欄位由於是varchar型別,可能比較長,為了更好的維護索引和減少索引佔用磁碟空間的大小,我們可以在列後面加上索引的長度. - 唯一索引 ``` sql create unique index idx_id on user(id); ``` ​ 主鍵索引是唯一索引的特殊型別,建議主鍵索引使用整數,整數佔用空間比較小.同樣可以為索引指定長度,如果是int型別就不需要指定了. - 組合索引 ``` sql create index idx_id_name_age on user(id,name(10),age); ``` - 最左字首原則: - 說明一點我們建立了以上組合索引的時候,相當於建立了是三個索引: - id,name,age - id,name - id ``` sql select * from user where age = 13 and id =1 and name = 'VN'; ``` 此時是否使用到了組合索引? 這種情況下是違反了最左字首原則,由於我們建立的索引的順序是id,name,age.我們在使用組合索引的時候應該也要遵循這個順序,如果打亂順序那麼就會導致索引失效.正確使用組合索引應該是以下sql語句: ``` sql select * from user where id = 1 and name = 'VN' and age = 13; ``` 還有以下情況,是否使用到了索引. ``` sql select * from user where id =1 and name = 'VN'; ``` ``` sql select * from user where id =1; ``` 以上兩條sql語句是正確使用了索引的,因為組合索引也可以拆開使用,但一定是有順序的,不能打亂,從打亂索引順序的時候開始,往後的索引就是失效了. ###### 切記:如果索引順序是以上情況,直接拿name,或者age來用,索引是失效的.因為違背的最左字首原則,即使把組合索引拆開來用,也一定是有序的. #### 刪除索引 ``` sql drop index idx_id_name_age on user; ``` #### 檢視索引 ``` sql show index from user \G; ``` ***** #### 索引的資料結構 在開始具體說索引的資料結構前,要說明一下,因為索引是mysql引擎中實現的,所以不同的儲存引擎有不同的實現.由於現在mysql中InnoDB是預設的資料庫引擎,並且我們大部分場景下使用的也是InnoDB引擎,所以在索引的資料結構這裡,我們只針對於InnoDB引擎來說. 索引的資料結構是什麼,相信我們大家都知道是B+tree,可具體什麼是B+TREE呢?B+TREE長什麼樣子呢?B-TREE和B+TREE的區別是什麼?這些問題大家就不一定都能回答上來了吧? ##### B-tree:(也叫做多路平衡樹) ![](https://upload-images.jianshu.io/upload_images/12058546-2ed176816eed54ad.png) ##### B+TREE: ![](https://images2017.cnblogs.com/blog/831179/201707/831179-20170727155517883-253845810.png) 以上兩種是b-tree和B+tree的樣子 ###### b+tree在MyISAM的實現: ![](https://upload-images.jianshu.io/upload_images/12058546-316168444236022b.png) MyISAM非聚集索引.非葉子節點只存放著指向具體的資料的地址值. ###### b+tree在InnoDB的實現: ![](https://upload-images.jianshu.io/upload_images/12058546-0da96cb9de1ff1c3.png) InnoDB聚集索引,非葉子節點存放有具體的資料. ###### b-tree和b+tree的區別 - b-tree葉子節點也是存放資料的,而b+tree只有非葉子節點存放資料,葉子節點存放的都是指向下一個節點的指標. - b+tree非葉子節點使用連結串列結構相鄰的兩個非葉子節點相連. #### 索引失效 在說索引失效之前,不得不先說一下explain檢視執行計劃. ##### 執行計劃 MySQL 提供了一個 EXPLAIN 命令, 它可以對 SELECT 語句的執行計劃進行分析, 並輸出 SELECT 執行的 詳細資訊, 以供開發人員針對性優化. 使用explain這個命令來檢視一個這些SQL語句的執行計劃,檢視該SQL語句有沒有使用上了索引,有沒 有做全表掃描,這都可以通過explain命令來檢視。 可以通過explain命令深入瞭解MySQL的基於開銷的優化器,還可以獲得很多可能被優化器考慮到的訪 問策略的細節,以及當執行SQL語句時哪種策略預計會被優化器採用。 用法如下: ![](http://q7dahrctq.bkt.clouddn.com/1584600225(1).jpg) 其中各列的含義如下: - id:select查詢的識別符號,每一個select有一個唯一的識別符號.標識查詢的執行順序. - id相同,執行順序從上往下 - id不同,如果是子查詢,id越大,優先順序越高 - select_type:select查詢的型別. - simple:簡單的select查詢 - parmary:一個union或者子查詢的操作,最外層的就是parmary - union:連線的兩個都是查詢,第一個是派生表dervied,往後的都是union - dependent union:出現在連線查詢中,受外部查詢影響 - subquery:除了from中的子查詢,其他地方的子查詢 - derived:from中出現的子查詢,和之前提到的一樣派生表 - table:查詢的那張表. - 如果使用了別名,這裡顯示別名 - 如果出現了尖括號,那說明是臨時表 - 如果不涉及表的操作,這裡顯示為null - partitions:匹配的分割槽. - type:連線型別 ​ **效能從好到差排序** - system:只有一行資料或者是空表 - const:使用唯一索引或者主鍵 - eq_ref:出現在多表關聯查詢,對於前表的每一個結果抖只能匹配到一條結果 - ref:非唯一索引,使用了組合索引符合最左字首 - fulltext:全文索引檢索 - ref_or_null:ref類似 - unique_subquery:where中的in的子查詢 - index_subquery:子查詢in形式子查詢使用到了輔助索引 - range:索引範圍掃描 - index_merge:使用了兩個以上的索引 - index:結果列中使用到了索引 - index - ALL:全表掃描 - 只有all沒有使用到索引,其他都使用到了索引 - 建議使用到range級別 - possible_keys: 此次查詢中可能選用的索引 - key: 此次查詢中確切使用到的索引. - ref: 哪個欄位或常數與 key 一起被使用 - rows: 顯示此查詢一共掃描了多少行. 這個是一個估計值. - filtered: 表示此查詢條件所過濾的資料的百分比 - extra: 額外的資訊 - using index:索引覆蓋,不需要回表掃描 - using where:對storage engine提取的結果進行過濾,改欄位沒有索引 - using filesort:排序中沒有使用到索引 - using temporary:使用了臨時表存結果 #### 索引下推 大家都知道mysql架構分為了server層和引擎層.索引下推也叫做ICP. ##### 如何處理where條件 - index_key:確定索引中的連續範圍,根據索引來確定範圍 - index_filter:index_key確定了索引範圍之後,還有一部分不符合條件,通過index_filter篩選 - table_filter:索引不能過濾的交給table_filter,也就是回表過濾 **torage層**: 首先將index key條件滿足的索引記錄區間確定,然後在索引上使用index filter進行過濾 將滿足的index filter條件的索引記錄才去回表取出整行記錄返回server層 不滿足index filter條件的索引記錄丟棄,不回表、也不會返回server層 **server 層**: 對返回的資料,使用table filter條件做最後的過濾。 ![]( http://q7dahrctq.bkt.clouddn.com/1584605179(1).jpg) 使用ICP的好處: - 直接去掉了不滿足index_filter的記錄,避免了回表和傳到server層 #### 索引失效 - 違反了最左字首原則會導致索引失效 - 索引上不要做計算,會導致索引失效 - 範圍條件右邊的列索引失效 - 索引欄位不要使用不等,會導致索引失效 - 索引欄位使用is null或者not null會導致索引失效 - 索引欄位使用or會導致索引失效 關於索引的資料結構推薦大家一片博文,講解的會更全面,本篇部落格中一部分圖片取自於該部落格. 地址是:https://www.cnblogs.com/aligege/p/11589398.html > 下一篇:mysql那些事之鎖