mysql系列【你不知道的索引優化】(面試必問)

前言:相信大家面試的時候肯定被問過這個問題,但很多都是因爲不夠深入,或者瞭解片面而導致好的機會和你失之交臂,其實這個問題答得好是非常加分的,好了不多說了開始…

1、什麼是索引?

  • 索引:索引(Index)是幫助MySQL高效獲取數據的數據結構。索引的目的在於提更高查詢效率,可以類比字典。
  • 常見的MySQL主要有兩種結構:Hash索引B+ Tree索引,我們使用的是InnoDB引擎,默認的是B+樹
  • 一般來說索引本身也很大,不可能全部存儲在內存中,因此索引往往以索引文件的形式存儲的磁盤上
  • 基本語法
    - 創建:
    - create index index_name on table(column(length))
    - alter table add index on (column(length))
    - 刪除:drop index index_name on table
    - 查看:show index from table

1.1、B+Tree結構瞭解一下

這裏簡單的聊下BTree的數據結構,首先看下面一個圖
在這裏插入圖片描述

【介紹】
首先一棵B+Tree,淺藍色的塊我們稱之爲一個磁盤塊,可以看到每個磁盤塊包含幾個數據項(深藍色所示)和指針(黃色所示),如磁盤塊1包含數據項17和35,包含指針P1、P2、P3,P1表示小於17的磁盤塊,P2表示在17和35之間的磁盤塊,P3表示大於35的磁盤塊。
真實的數據存在於葉子節點即3、5、9、10、13、15、28、29、36、60、75、79、90、99。
非葉子節點不存儲真實的數據,只存儲指引搜素方向的數據項,如17、35並不真實存在於數據表中。
【查找過程】
如果要查找數據項29,那麼首先會把磁盤塊1由磁盤加載到內存,此時發生一次l0,在內存中用二分查找確定29在17和35之間,鎖定磁盤塊1的P2指針,內存時間因爲非常短(相比磁盤的IO)可以忽略不計通過磁盤塊1的P2指針的磁盤地址把磁盤塊3由磁盤加載到內存,發生第二次IO,29在26和30之間,鎖定磁盤塊3的P2指針,通過指針加載磁盤塊8到內存,發生第三次lO,同時內存中做二分查找找到29,結束查詢,總計三次lO。

1.2、索引到底有哪些

普通索引:僅加速查詢

唯一索引:加速查詢 + 列值唯一(可以有null)

主鍵索引:加速查詢 + 列值唯一(不可以有null)+ 表中只有一個

組合索引:多列值組成一個索引,專門用於組合搜索,其效率大於索引合併

全文索引:對文本的內容進行分詞,進行搜索

覆蓋索引,select的數據列只用從索引中就能夠取得,不必讀取數據行,換句話說查詢列要被所建的索引覆蓋

1.3、索引是把雙刃劍

優點

  1. 通過創建唯一索引,可以保證數據庫每一行數據的唯一性
  2. 可以大大提高查詢速度
  3. 可以加速表與表的連接
  4. 可以顯著的減少查詢中分組和排序的時間

缺點

  1. 創建索引和維護索引需要時間,而且數據量越大時間越長
  2. 創建索引需要佔據磁盤的空間,如果有大量的索引,可能比數據文件更快達到最大文件尺寸
  3. 當對錶中的數據進行增加,修改,刪除的時候,索引也要同時進行維護,降低了數據的維護速度

2、索引優化

  • 讓索引效率更高:這其中就涉及到索引的選擇性了,索引的選擇性是指索引列中不同值的數目與表中記錄數的比。如果一個表中有2000條記錄,表索引列有1980個不同的值,那麼這個索引的選擇性就是1980/2000=0.99。一個索引的選擇性越接近於1,這個索引的效率就越高

mysql中其實優化的方面有很多,但是最讓我們容易想到的就是索引優化
,但在這之前你需要了解一個東西…

2.1、其中最重要的就是這個explain關鍵字

以下標紅的爲常用字段

字段 含義
id select查詢的序列號,包含一組數字,表示查詢中執行select子句或操作表的順序
select_type 查詢的類型
table 當前行所查的表
partitions 匹配的分區
type 訪問類型(system>const>eq_ref>ref>range>index>all)
possible_keys 可能用到的索引
key 真實用到的索引,沒有用到的爲null
key_len 索引 key 的長度
ref 顯示了之前的表在key列記錄的索引中查找值所用的列或常量
rows 查詢掃描的行數,預估值,不一定準確
filtered 查詢的錶行佔表的百分比
extra 額外的查詢輔助信息

這裏說下這些常用的字段:
id:select查詢的序列號,包含一組數字,表示查詢中執行select子句或操作表的順序
這裏有三種情況:
情況一:id不同,如果是子查詢,id的值會遞增,id值越大,優先級越高
情況二:id相同,執行順序從上到下
情況三:同屬存在,id如果相同,可以認爲是一組,從上往下順序執行;在所有組中,id值越大,優先級越高,越先執行

type:顯示查詢使用了何種類型,從最好到最差依次是:

system const eq_ref ref range index all

一般來說,得保證查詢至少達到range級別,最好能達到ref

  • system 表只有一行記錄(等於系統表),這是const類型的特列,平時不會出現,這個也可以忽略不計

  • const表示通過索引一次就找到了,const用於比較primary key或者unique索引。因爲只匹配一行數據,所以很快const 如將主鍵置於where列表中,MySQL就能將該查詢轉換爲一個常量

  • eq_ref唯一性索引掃描,對於每個索引鍵,表中只有一條記錄與之匹配。常見於主鍵或唯一索引掃描
    ref非唯一性索引掃描,返回匹配某個單獨值的所有行.

  • ref本質上也是一種索引訪問,它返回所有匹配某個單獨值的行,然而,ref可能會找到多個符合條件的行,所以他應該屬於查找和掃描的混合體

  • range只檢索給定範圍的行,使用一個索引來選擇行。key列顯示使用了哪個索引一般就是在你的where語句中出現了between、<、>、in等的查詢range 這種範圍掃描索引掃描比全表掃描要好,因爲它只需要開始於索引的某一點,而結束語另一點,不用掃描全部索引。

  • index:Full Index Scan,index與ALL區別爲index類型只遍歷索引樹。這通常比ALL快,因爲索引文件通常比數據文件小。(也就是說雖然all和Index都是讀全表,但index是從索引中讀取的,而all是從硬盤中讀的)

  • all:Full Table Scan,將遍歷全表以找到匹配的行

key:實際使用的索引。如果爲NULL則沒有使用,索引查詢中若使用了覆蓋索引,則該索引僅出現在key列表中

覆蓋索引:就是select的數據列只用從索引中就能夠取得,不必讀取數據行,MySQL可以利用索引返回select列表中的字段,而不必根據索引再次讀取數據文件,換句話說查詢列要被所建的索引覆蓋

Extra

  • Using filesort 說明mysql會對數據使用一個外部的索引排序,而不是按照表內的索引順序進行讀取。MySQL中無法利用索引完成的排序操作稱爲“文件排序”,簡單來說查詢用到了,排序沒有用到
  • Using temporary使了用臨時表保存中間結果,MySQL在對查詢結果排序時使用臨時表。常見於排序order by和分組查詢 grgup by。
  • 上面兩個優化最好使用覆蓋索引
    -Using index 表示相應的select操作中使用了覆蓋索引(Covering Index),避免訪問了表的數據行,效率不錯!如果同時出現using where,表明索引被用來執行索引鍵值的查找;如果沒有同時出現Using where,表明索引用來讀取數據而非執行查找動作。
  • Using where表明使用了where過濾
  • Using join buffer :使用了連接緩存
  • impossiable where : where子句的值總是false,不能用來獲取任何元組
  • distinct :優化distinct操作,在找到第一匹配的元組後即停止找同樣值的動作
  • select tables optimized away:在沒有GROUPBY子句的情況下,基於索引優化MIN/MAX操作或者對於MyISAM存儲引擎優化COUNT(*)操作,不必等到執行階段再進行計算,查詢執行計劃生成的階段即完成優化。

注意: 如果要使用覆蓋索引,一定要注意select列表中只取出需要的列,不可select *
因爲如果將所有字段一起做索引會導致索引文件過大,查詢性能下降

知道這些後想必你對mysql優化有進一步的瞭解,接下來看看有哪些情況會使索引失效

2.2、使用索引的注意事項

哪些優化情況下需要創建索引?

  1. 主鍵自動建立唯一索引
  2. 頻繁作爲查詢條件的字段應該創建索引
  3. 查詢中與其它表關聯的字段,外鍵關係建立索引
  4. 單鍵/組合索引的選擇問題,(在高併發下傾向創建組合索引)
  5. 查詢中排序的字段,排序字段若通過索引去訪問將大大提高排序速度
  6. 查詢中統計或者分組字段

哪些情況我們不必要創建它?

  1. 表記錄太少。
  2. 經常增刪改的列。
  3. 如果某個數據列包啥許多重複的內容,爲它建立索引就沒有太大的實際效果。

2.3、導致索引失效的原因哪些(索引優化方案)?

  1. 違背最佳左前綴法則(複合索引情況下:索引的順序和查詢的字段儘量保持一致)
  2. 不在索引列上做任何操作(計算、函數、(自動or手動)類型轉換),會導致索引失效而轉向全表掃描
  3. 存儲引擎不能使用索引中範圍條件右邊的列(range後面的索引都失效)
  4. mysql在使用不等於(!=或者<>)的時候無法使用索引會導致全表掃描
  5. is null,is not null 也無法使用索引
  6. like以通配符開頭(“%abc.…)mysql索引失效會變成全表掃描的操作
    解決:如果解決%xxx%索引失效,可以使用複合索引解決,就是查詢的字段和 索引的列相同,或者是全文索引
  7. 字符串不加單引號索引失效
  8. 少用or,用它來連接時會索引失效(可以用union all代替)
  9. type等於range類型查詢字段後面的素引無效。
  10. 索引單表優化:當 explain的type頭中的數據是range的時候 那麼這個索引後面的索引會失效
  11. 索引兩表優化:左外連接的時候索引要建立在右邊的字段上,因爲left_join左邊全查,右邊的根據條件進行查詢,所以右邊爲關鍵點一定要建立索引
  12. 索引三表優化:同兩表
    儘可能減少Join語句中的NestedLoop的循環總次數;“永遠用小結果集驅動大的結果集”。
  13. 對於單鍵索引,儘量選擇針對當前query過濾性更好的索引
  14. 在選擇組合索引的時候,當前Query中過濾性最好的字段在索引字段順序中,位置越靠前越好。
  15. 在選擇組合索引的時候,儘量選擇可以能夠包含當前query中的where字句中更多字段的索引
  16. 儘可能通過分析統計信息和調整query的寫法來達到選擇合適索引的目的

結言:歡迎評論區留言 ,喜歡博文可以給個👍呦,也可以關注我【jar殼蟲】,後續會有更多分享🎈🎈

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章