前言
由於MySQL的索引中最重要的資料結構就是B+樹,所以前面我們先大概講講B+樹的原理
B+ Tree 原理
1. 資料結構
B+ Tree 是基於 B Tree 和葉子節點順序訪問指標進行實現,它具有 B Tree 的平衡性,並且通過順序訪問指標來提高區間查詢的效能。
2. 操作
插入刪除操作會破壞平衡樹的平衡性,因此在插入刪除操作之後,需要對樹進行一個分裂、合併、旋轉等操作來維護平衡性。
3. 與紅黑樹的比較
(一)更少的查詢次數
(二)利用磁碟預讀特性
作業系統一般將記憶體和磁碟分割成固態大小的塊,每一塊稱為一頁,記憶體與磁碟以頁為單位交換資料。資料庫系統將索引的一個節點的大小設定為頁的大小,使得一次 I/O 就能完全載入一個節點。並且可以利用預讀特性,相鄰的節點也能夠被預先載入。
MySQL 索引
1. B+Tree 索引
因為不再需要進行全表掃描,只需要對樹進行搜尋即可,所以查詢速度快很多。
可以指定多個列作為索引列,多個索引列共同組成鍵。
InnoDB 的 B+Tree 索引分為主索引和輔助索引。主索引的葉子節點 data 域記錄著完整的資料記錄,這種索引方式被稱為聚簇索引。因為無法把資料行存放在兩個不同的地方,所以一個表只能有一個聚簇索引。
2. 雜湊索引
- 無法用於排序與分組;
- 只支援精確查詢,無法用於部分查詢和範圍查詢。
3. 全文索引
4. 空間資料索引
索引優化
1. 獨立的列
在進行查詢時,索引列不能是表示式的一部分,也不能是函式的引數,否則無法使用索引。
例如下面的查詢不能使用 actor_id 列的索引:
SELECT actor_id FROM sakila.actor WHERE actor_id + 1 = 5;複製程式碼
2. 多列索引
在需要使用多個列作為條件進行查詢時,使用多列索引比使用多個單列索引效能更好。例如下面的語句中,最好把 actor_id 和 film_id 設定為多列索引。
SELECT film_id, actor_ id FROM sakila.film_actor WHERE actor_id = 1 AND film_id = 1;複製程式碼
3. 索引列的順序
讓選擇性最強的索引列放在前面。
索引的選擇性是指:不重複的索引值和記錄總數的比值。最大值為 1,此時每個記錄都有唯一的索引與其對應。選擇性越高,查詢效率也越高。
例如下面顯示的結果中 customer_id 的選擇性比 staff_id 更高,因此最好把 customer_id 列放在多列索引的前面。
SELECT COUNT(DISTINCT staff_id)/COUNT(*) AS staff_id_selectivity,
COUNT(DISTINCT customer_id)/COUNT(*) AS customer_id_selectivity,
COUNT(*)
FROM payment;複製程式碼
staff_id_selectivity: 0.0001
customer_id_selectivity: 0.0373
COUNT(*): 16049複製程式碼
4. 字首索引
對於 BLOB、TEXT 和 VARCHAR 型別的列,必須使用字首索引,只索引開始的部分字元。
對於字首長度的選取需要根據索引選擇性來確定。
5. 覆蓋索引
索引包含所有需要查詢的欄位的值。
具有以下優點:
- 索引通常遠小於資料行的大小,只讀取索引能大大減少資料訪問量。
- 一些儲存引擎(例如 MyISAM)在記憶體中只快取索引,而資料依賴於作業系統來快取。因此,只訪問索引可以不使用系統呼叫(通常比較費時)。
- 對於 InnoDB 引擎,若輔助索引能夠覆蓋查詢,則無需訪問主索引。
6. 最左字首原則
聯合索引本質:
索引的優點
- 大大減少了伺服器需要掃描的資料行數。
- 幫助伺服器避免進行排序和分組,以及避免建立臨時表(B+Tree 索引是有序的,可以用於 ORDER BY 和 GROUP BY 操作。臨時表主要是在排序和分組過程中建立,因為不需要排序和分組,也就不需要建立臨時表)。
- 將隨機 I/O 變為順序 I/O(B+Tree 索引是有序的,會將相鄰的資料都儲存在一起)。
索引的使用條件
- 對於非常小的表、大部分情況下簡單的全表掃描比建立索引更高效;
- 對於中到大型的表,索引就非常有效;
- 但是對於特大型的表,建立和維護索引的代價將會隨之增長。這種情況下,需要用到一種技術可以直接區分出需要查詢的一組資料,而不是一條記錄一條記錄地匹配,例如可以使用分割槽技術。
小結
索引是MySQL中一個很重要的功能,日常開發中如果能用好索引,能大幅度提高SQL語句的執行效能,所以瞭解其中的原理也是十分必要的。
文章大部分參考自