MySQL專題—— 從認識索引到理解索引【索引優化】

認識索引

認識索引是什么東西非常關鍵,一個非常恰當的比喻就是書的目錄頁與書的正文內容之間的關系,為了方便查找書中的內容,通過對內容建立索引形成目錄。因此,首先你要明白的一點就是,索引它也是一個文件,它是要占據物理空間的。

比如對于MyISAM存儲引擎來說:

.frm后綴的文件存儲的是表結構。

.myd后綴的文件存儲的是表數據。

.myi后綴的文件存儲的就是索引文件。

  如下圖所示:

對于InnoDB存儲引擎來說:

.frm

.ibd后綴的文件存放索引文件和數據(需要開啟innodb_file_per_table參數)

  如下圖所示:

因此,當你對一張表建立索引時,索引文件的大小也會改變,當你數據表中的數據因為增刪改變化時,索引文件也會變化的,只不過MySQL會自動維護索引,這個過程不需要你介入,這也是為什么不恰當的索引會影響MySQL性能的原因。

總結:

1. 索引是按照特定的數據結構把數據表中的數據放在索引文件中,以便于快速查找;

2. 索引存在于磁盤中,會占據物理空間。

索引的類型

B-Tree 索引

  以 B-Tree 為結構的索引是最常見的索引類型,比如 InnoDB 和 MyISAM 都是以 B-Tree 為索引結構的索引,事實上是以 B+ Tree 為索引結構,B-Tree 和 B+Tree 區別在于,B+ Tree 在葉子節點上增加了順序訪問指針,方便葉子節點的范圍遍歷。這里主要介紹一下 InnoDB 和 MyISAM。

InnoDB

  InnoDB 支持聚簇索引,聚簇索引和非聚簇索引嚴格來說不是一種索引,而是一種數據存儲方式,這個名字跟它本身的存儲方式有關系,“聚簇“表示數據行和相鄰的鍵值存儲在一起,簡單的說,就是葉子節點中存儲的實際是真實的數據。InnoDB 通過主鍵聚集數據,所以一個表只能有一個聚簇索引,且必須有主鍵,如果沒有定義主鍵,且不存在非空索引可以代替,InnoDB 會隱式定義一個主鍵作為聚簇索引。

  聚簇索引的二級索引存儲的不是指向行的物理位置的指針,而是行的主鍵值,所以如果通過二級索引查找行,需要找到二級索引的葉子結點獲得對應的主鍵值,然后再去查找對應的行。對于 InnoDB,自適應哈希索引可以減少這樣的重復工作。

  InnoDB 使用的是行鎖,所以支持事務,而 MyISAM 使用的是表鎖,不支持事務。

適用范圍

  B-Tree 索引適用于區間查詢,因為 B-Tree 存儲后的葉子節點本身就是有序的,并且 B+ Tree 結構還增加了葉子節點的連續順序指針,對于區間查詢來說就更加方便了。

哈希索引

  哈希索引是基于哈希表實現的,只有精確匹配索引所有列的查詢才有效。方法是,對所有的索引列計算一個 hash code,hash code 作為索引,在哈希表中保存指向每個數據行的指針。

優點

  索引本身只存儲 hash code,所以結構很緊湊,并且查找速度很快

  限制

  索引中的 hash code 是順序存儲的,但是 hash code 對應的數據并不是順序的,所以無法用于排序

  不支持部分索引列匹配查找,因為哈希索引是使用索引列的全部內容來計算 hash code

  只支持等值比較,不支持范圍查詢

  如果哈希沖突嚴重時,必須遍歷鏈表中所有行指針

  哈希沖突嚴重的話,索引維護操作的代價也很高

  InnoDB 的自適應哈希索引

  首先,請注意,自適應哈希索引對于用戶來說是無感知的,這是一個完全自動、內部的行為,用戶無法控制或者配置,但是可以關閉。

  當 InnoDB 注意到某個索引值被使用的非常頻繁時,它會在內存中基于 B-Tree 索引之上再創建一個哈希索引,這樣 B-Tree 也可以具有哈希索引的一些優點,比如快速的哈希查找。

當然如果存儲引擎不支持哈希索引,用戶也可以自定義哈希索引,這樣性能會比較高,缺陷是需要自己維護哈希值,如果采用這種方法,不要使用?SHA1()?和?MD5()?作為哈希函數,因為這兩個是強加密函數,設計目標是最大限度消除沖突,生成的 hash code 是一個非常長的字符串,浪費大量的空間,哈希索引中對于索引的沖突要求沒有那么高。

索引的優點

  使用索引可以減少服務器需要掃描的數據量

  使用索引可以幫助服務器避免排序和臨時表

  使用索引可以將隨機 I/O 變為順序 I/O

  但是不是所有情況下,索引都是最好的解決方案,對于非常小的表來說,大部分情況下簡單的全表掃描更高效,對于中到大型表,索引就比較有效,對于特大型的表來說,分區會更加有效。

常見優化方法

聯合索引最左前綴原則

  復合索引遵守「最左前綴」原則,查詢條件中,使用了復合索引前面的字段,索引才會被使用,如果不是按照索引的最左列開始查找,則無法使用索引。

  比如在(a,b,c)三個字段上建立聯合索引,那么它能夠加快a|(a,b)|(a,b,c)三組查詢的速度,而不能加快b|(b,a)這種查詢順序。

  另外,建聯合索引的時候,區分度最高的字段在最左邊。

不要在列上使用函數和進行運算

  不要在列上使用函數,這將導致索引失效而進行全表掃描。

  例如下面的 SQL 語句:

select * from artile where YEAR(create_time) <= '2018'; 復制代碼

  即使 date 上建立了索引,也會全表掃描,可以把計算放到業務層,這樣做不僅可以節省數據庫的 CPU,還可以起到查詢緩存優化效果。

負向條件查詢不能使用索引

  負向條件有:!=、<>、not in、not exists、not like 等。

select * from artile where status != 1 and status != 2; 復制代碼

  可以使用in進行優化:

select * from artile where status in (0,3) 復制代碼

使用覆蓋索引

  所謂覆蓋索引,是指被查詢的列,數據能從索引中取得,而不用通過行定位符再到數據表上獲取,能夠極大的提高性能。

  可以定義一個讓索引包含的額外的列,即使這個列對于索引而言是無用的。

避免強制類型轉換

  當查詢條件左右兩側類型不匹配的時候會發生強制轉換,強制轉換可能導致索引失效而進行全表掃描。

  如果phone字段是varchar類型,則下面的SQL不能命中索引:

select * from user where phone=12345678901; 復制代碼

  可以優化為:

select * from user where phone='12345678901'; 復制代碼

范圍列可以用到索引

  范圍條件有:<、<=、>、>=、between等。

  范圍列可以用到索引,但是范圍列后面的列無法用到索引,索引最多用于一個范圍列,如果查詢條件中有兩個范圍列則無法全用到索引。

更新頻繁、數據區分度不高的字段上不宜建立索引

  更新會變更B+樹,更新頻繁的字段建立索引會大大降低數據庫性能。

  「性別」這種區分度不大的屬性,建立索引沒有意義,不能有效過濾數據,性能與全表掃描類似。

  區分度可以使用 count(distinct(列名))/count(*) 來計算,在80%以上的時候就可以建立索引。

索引列不允許為null

  單列索引不存null值,復合索引不存全為null的值,如果列允許為 null,可能會得到不符合預期的結果集。

避免使用or來連接條件

  應該盡量避免在 where 子句中使用 or 來連接條件,因為這會導致索引失效而進行全表掃描,雖然新版的MySQL能夠命中索引,但查詢優化耗費的 CPU比in多。

模糊查詢

  前導模糊查詢不能使用索引,非前導查詢可以。

  需要學習更多java相關知識請關注我,或者查看我的往期發布哦

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,505評論 6 533
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,556評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 176,463評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,009評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,778評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,218評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,281評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,436評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,969評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,795評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,993評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,537評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,229評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,659評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,917評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,687評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,990評論 2 374

推薦閱讀更多精彩內容