MySQL 索引解析:讓查詢速度飆升的秘訣!
1.前言
這次小編準備用兩篇文章來和大家分享下mysql innodb的索引: mysql的基礎知識 和 基于索引的sql優化 。
2. 什么是索引?
定義:索引是數據庫中用于快速查找數據的機制,本質是某種數據結構。它存儲著指向數據的指針,從而幫助數據庫跳過不必要的行,直接定位到目標數據,減少掃描時間。
比如我們看<<三國演義>>劉備三顧茅廬這章,如果沒有目錄,我們就需要一篇一篇的翻書,要翻很久,因為不知道在書的哪一頁;但是如果有目錄,我們是不是先在目錄里面找到這章的目錄,這章的目錄對應著正文的書頁,我們一下就可以翻到對應的書頁,找到對應的章節。目錄就類似于mysql的索引。
3. 為什么需要索引?
- 加速查詢:索引可以顯著減少數據庫檢索所需的時間。沒有索引時,數據庫會執行全表掃描(讀取每一行),而索引讓數據庫只需要掃描部分數據。
- 降低 I/O 負載:索引通過減少物理讀取的次數,從而減少 I/O 操作。在大型數據集上尤其明顯,特別是對于復雜查詢或多表連接(JOIN)的場景。
- 常見應用場景:索引在以下場景中最有用:
WHERE 子句中的條件過濾。
ORDER BY 語句進行排序時。
GROUP BY 語句進行分組時。
多表 JOIN 操作時匹配外鍵或其他相關列。
4. 索引的類型
- 主鍵索引:主鍵是表中唯一標識記錄的字段,通常自動創建索引。InnoDB 存儲引擎會將主鍵索引作為聚簇索引(Clustered Index),即數據的物理存儲順序和主鍵索引順序一致。
- 唯一索引:保證索引列中的所有值唯一性,類似于主鍵索引,但可以應用于非主鍵字段。
- 普通索引:沒有唯一性要求的索引,用于加速查詢的非主鍵列。普通索引僅保證加速查找,沒有其他約束。
- 聯合索引(復合索引):一個索引包含多個列,按照指定順序進行索引。根據最左前綴原則,只要查詢的條件從左開始匹配列的順序,索引就可以生效。
5. 索引的結構
- B-Tree 索引:MySQL 中最常見的索引結構是 B-Tree,特別是 InnoDB 存儲引擎。B-Tree 索引通過一種平衡樹結構,使得數據查找時間復雜度為 O(log n)。每個節點存儲鍵值,并且有指向下層節點的指針。查詢通過層次結構逐級縮小搜索范圍,從而快速定位目標數據。
- 哈希索引:哈希索引基于哈希函數,將鍵值映射為固定大小的哈希值。其特點是查詢效率極高(O(1) 時間復雜度),但只適用于精確匹配的查詢。不支持范圍查詢(例如 <、> 操作),因此哈希索引不適合大多數通用場景。
這里強調一下:innodb只能創建B-Tree 索引,不支持哈希索引。即使創建的時候選擇的是哈希,實際創建之后的結果也是B-Tree,有興趣的同學可以試試,小編這里就不截圖了。
下面,小編用六條數據模擬下索引的結構。首先看下表結構:
圖片
然后表里面的數據:
圖片
然后看下主鍵索引的結構,這里是小編根據索引的結構自己畫的:
圖片
根據這個B+ 樹索引結構圖,小編簡單的說下:
- 綠色: 綠色框框表示頁數,之前已經講過,數據庫的數據是以頁的方式存儲。
- 紅色: 紅色框框表示是否是索引還是數據行,1:索引;0:數據。
- B+樹的葉子節點存放的是完整的數據,非葉子節點存放的是索引數據。
- B+樹的子節點可以有多個,這里是只用4條數據模擬,多了難得畫。
- 葉子節點的數據是有序的,根據主鍵id由小到大存儲,并且行與行,頁與頁之間是用雙向鏈表連接的。
二級索引
除了主鍵外,我們會根據查詢的字段,也去建立相應的字段索引。小編這里就不畫圖了,二級索引的葉子節點放的是對應的主鍵索引值。
回表
指的是 MySQL 在通過二級索引查找到符合條件的記錄后,還需要回到主鍵索引中去讀取額外的列數據。因為索引只包含部分列的信息,如果查詢中請求了索引中未包含的列,數據庫就需要從主鍵索引中再次讀取完整的行數據。
比如user表中,我給name添加索引,我需要查詢name=小九這行數據的信息,因為二級索引是沒有完整的數據,所以mysql需要去主鍵索引里面找到對應的完整數據返回。
覆蓋索引
指的是當一個索引完全包含了查詢所需的所有列時,MySQL 不需要再回表,而是直接從索引中就可以返回結果。這種情況就稱為覆蓋索引。
比如user表中,我給name添加索引,我需要查詢name=小九這條數據的id,因為id在葉子節點已經有了,直接就返回了結果,不需要去主鍵索引再次查詢。
覆蓋索引的優勢:
性能提升:避免了回表,降低了 I/O 和查詢時間。減少表掃描:索引的存儲比表的數據量小得多,索引掃描比全表掃描快。
6. 總結
- 索引是提升查詢性能的關鍵工具,選擇合適的索引類型和合理優化可以極大提高數據庫效率。
- 理解索引的類型和底層原理能夠幫助開發者在構建數據庫時做出明智的決策。