深刻理解MySQL系列之索引

索引

查找一條數據的過程

先看下InnoDB的邏輯存儲結構:node

  1. 表空間:能夠看作是InnoDB存儲引擎邏輯結構的最高層,全部的數據都存放在表空間中。默認有個共享表空間ibdata1。若是啓用innodb_file_per_table參數,須要注意每張表的表空間內存放的只是數據、索引和插入緩衝Bitmap頁,其餘類的數據,如回滾信息、插入緩衝索引頁、系統事務信息、二次寫緩衝等仍是存放在原來共享表空間中。數據庫

  2. 段:
    表空間是由各個段組成,常見的段有數據段、索引段、回滾段等。數據段即爲B+樹葉子節點(Leaf node segment),索引段即爲B+樹非葉子節點(Non-leaf node segment)
    性能

  3. 區:是由連續頁組成的空間,在任何狀況下每一個區大小都爲1MB。默認狀況下,存儲引擎頁的大小爲16KB,即一個區中一共有連續64個連續的頁。而爲保證頁的連續性,InnoDB存儲引擎一次從磁盤申請4-5個區。優化

  4. 頁:
    頁(也能夠稱塊),是InnoDB磁盤管理的最小單位。默認每一個頁大小16KB。1.2x版本後也能夠經過參數innodb_page_size設置爲4k、8k、16k3d

如查一條數據:select * from user where id=5;指針

這裏id是主鍵,咱們經過這棵B+樹來查找,首先會去找到根頁,每張表的根頁位置在表空間文件中是固定的;找到根頁後經過二分查找法,定位到id=5的數據應該在指針P5指向的頁中,那麼進一步去page number=5的頁中查找,一樣經過二分查詢法便可找到id=5的記錄:blog

計算一棵B+樹能夠存放多少行數據

也能夠經過命令查看InnoDB每頁默認16KB:排序

show variables like 'innodb_page_size';索引

先計算非葉子節點, 假設主鍵ID爲bigint類型,長度爲8字節,而指針大小在InnoDB源碼中設置爲6字節,這樣一共14字節事務

而一個頁中能存放多少這樣的單元,其實就表明有多少指針,即16384/14=1170。

那麼能夠算出一棵高度爲2的B+樹,能存放1170*16=18720條這樣的數據記錄。

根據一樣的原理咱們能夠算出一個高度爲3的B+樹能夠存放:1170117016=21902400條這樣的記錄。

因此在InnoDB中B+樹高度通常爲1-3層,它就能知足千萬級的數據存儲。

索引一些概念
  1. 聚簇索引(clustered index): 就是將索引和數據放到一塊兒,找到索引也就找到了數據;以下圖葉子節點存放一行全部數據。

  1. 輔助索引(Secondary Index或非聚簇索引): 就是將數據和索引分開,查找時須要先查找到索引,而後經過索引回表找到相應的數據。
    回表:先經過數據庫索引掃描出數據所在的行,再經過行主鍵id取出索引中未提供的數據,即基於非主鍵索引的查詢須要多掃描一棵索引樹。

以下圖,輔助索引查找後,會再回表到聚簇索引,最後找到數據。

InnoDB有且只有一個聚簇索引,而MyISAM中都是非聚簇索引。

  1. 聯合索引:指對錶上多個列進行索引。

聯合索引的最左前綴匹配原則: 對多個字段同時創建的組合索引(有順序,ABC,ACB是徹底不一樣的兩種聯合索引) 以聯合索引(a,b,c)爲例,創建這樣的索引至關於創建了索引a、ab、abc三個索引。另外組合索引實際仍是一個索引,並不是真的建立了多個索引,只是產生的效果等價於產生多個索引。

  1. 覆蓋索引: 即從輔助索引中就能夠獲得查詢的記錄,而不須要查詢聚簇索引中的記錄。

使用覆蓋好處:

  • 輔助索引不包含整行記錄的全部信息,故其大小要遠小於聚簇索引,減小大量IO操做。
  • 對某些統計(如count(id))並不會經過查詢聚簇索引來進行統計,減小IO操做
  1. 惟一索引:以惟一列生成的索引,該列不容許有重複值,但容許有空值(NULL)

  2. 索引下推:MySQL 5.6引入了索引下推優化,能夠在索引遍歷過程當中,對索引中包含的字段先作判斷,過濾掉不符合條件的記錄,減小回表字數。

爲何選B+樹,而不是B樹

B樹無論葉子節點仍是非葉子節點,都會保存數據,這樣致使在非葉子節點中能保存的指針數量變少

指針少的狀況下要保存大量數據,只能增長樹的高度,致使IO操做變多,查詢性能變低;

爲何InnoDB只有一個聚簇索引,而不將全部索引都使用聚簇索引?

由於聚簇索引是將索引和數據都存放在葉子節點中,若是全部的索引都用聚簇索引,則每個索引都將保存一份數據,會形成數據的冗餘,在數據量很大的狀況下,這種數據冗餘是很消耗資源的。

什麼狀況下會發生明明建立了索引,可是執行的時候並無經過索引呢?

查詢優化器。

一條SQL語句的查詢,能夠有不一樣的執行方案,至於最終選擇哪一種方案,須要經過優化器進行選擇,選擇執行成本最低的方案。

優化過程大體以下:

  • 一、根據搜索條件,找出全部可能使用的索引
  • 二、計算全表掃描的代價
  • 三、計算使用不一樣索引執行查詢的代價
  • 四、對比各類執行方案的代價,找出成本最低的那一個 。
索引的優缺點

索引的優勢以下:

  • 一、惟一索引能夠保證每一行數據的惟一性
  • 二、提升查詢速度
  • 三、加速表與表的鏈接
  • 四、顯著的減小查詢中分組和排序的時間
  • 五、經過使用索引,能夠在查詢的過程當中,使用優化隱藏器,提升系統的性能。

索引的缺點以下:

  • 建立索引時,須要對錶加鎖,在鎖表的同時,可能會影響到其餘的數據操做
  • 雖然索引大大提升了查詢速度,同時卻會下降更新表的速度,如對錶進行 INSERT、UPDATE 和 DELETE。由於更新表時,MySQL 不只要保存數據,還要保存索引文件。
  • 創建索引會佔用磁盤空間的索引文件。通常狀況這個問題不算嚴重,但若是你在一個大表上建立了多種組合索引,且伴隨大量數據量插入,索引文件大小也會快速膨脹。
  • 若是某個數據列包含許多重複的內容,爲它創建索引就沒有太大的實際效果。
  • 對於很是小的表,大部分狀況下簡單的全表掃描更高效。
使用索引時的注意事項

原則:
不該該

一、索引不是越多越好。索引太多,維護索引須要時間跟空間
二、 頻繁更新的數據,不宜建索引。
三、數據量小的表不必創建索引。

應該

一、重複率小的列建議生成索引。由於重複數據少,索引樹查詢更有效率,等價基數越大越好。
二、數據具備惟一性,建議生成惟一性索引。在數據庫的層面,保證數據正確性
三、頻繁group by、order by的列建議生成索引。能夠大幅提升分組和排序效率
四、常常用於查詢條件的字段建議生成索引。經過索引查詢,速度更快

索引失效的場景

一、模糊搜索:左模糊或全模糊都會致使索引失效,好比'%a'和'%a%'。可是右模糊是能夠利用索引的,好比'a%'
二、隱式類型轉換:好比select * from t where name = xxx , name是字符串類型,可是沒有加引號,因此是由MySQL隱式轉換的,因此會讓索引失效
三、當語句中帶有or的時候:好比select * from t where name=‘sw’ or age=14
四、不符合聯合索引的最左前綴匹配:(A,B,C)的聯合索引,你只where了C或B或只有B,C

其餘注意事項:

  1. 索引不會包含有 null 值的列,只要列中包含有 null值都將不會被包含在索引中。
  2. 使用短索引。短索引不只能夠提升查詢速度並且能夠節省磁盤空間和 I/O 操做
  3. 索引列排序。查詢只使用一個索引,所以若是 where 子句中已經使用了索引的話,那麼 order by 中的列是不會使用索引的。所以數據庫默認排序能夠符合要求的狀況下不要使用排序操做;儘可能不要包含多個列的排序,若是須要最好給這些列建立複合索引。
  4. 不要在列上進行運算,這將致使索引失效而進行全表掃描
  5. 不使用 not in 和 <> 操做,這不屬於支持的範圍查詢條件,不會使用索引。

《MySQL技術內幕》
https://mp.weixin.qq.com/s/6j64s9W6ogs5Y8BbhhkgnA
https://mp.weixin.qq.com/s/KB73550tKpNccW-WKxT7-A
https://mp.weixin.qq.com/s/ovMx9Dv9NCFxSsFM98uYFw

相關文章
相關標籤/搜索