MySql數據庫索引詳解,索引看這一篇就夠了

目錄

1 爲什麼要使用索引?

2 索引的分類

3 索引的創建和刪除

4 索引的執行過程

5 索引的底層實現原理

6 主鍵索引,輔助索引,聚集索引,非聚集索引

6.1 MyISAM存儲引擎-主鍵索引

6.2 MyISAM存儲引擎-輔助索引

6.3 InnoDB存儲引擎-主鍵索引

6.4 InnoDB存儲引擎-輔助索引

7 索引的相關問題

7.1 索引的設計原則

7.2 一次查詢只能使用一個索引?

7.3 所有的查詢語句都能用到索引嗎?

 


推薦書籍《mysql索引漫畫》,書籍鏈接如下:

鏈接:https://pan.baidu.com/s/1Vh4N_S0pPd9_sYN04cIUsw
提取碼:b8or 

1 爲什麼要使用索引?

索引就像書籍的目錄,當我們要查找要看的內容的時候,先從目錄開始,找到內容對應的頁數,再翻到相應的頁去查看就可以了,這樣通過目錄去查找的方式比我們一頁一頁去查找效率高出很多,所以索引的核心就是加快SQL的查詢。

如果表中的數據量非常大,那麼一個SQL查詢花費的時間是非常長的,那麼此時應用索引來提升查詢的效率就是非常有必要的。

同時由於索引也是需要存儲成索引文件的,因此對索引的使用會涉及大量的磁盤I/O操作,如果索引創建過多,使用不當,那麼在SQL查詢的時候就會進行大量的磁盤I/O操作,這樣反而降低了查詢的效率。因此,對索引的執行過程和實現原理進行進一步的理解就顯得特別重要。

2 索引的分類

首先,索引是創建在表中的字段上的,是對數據庫表中的一列或者多列進行排序的結果。

按照索引字段可以將索引分爲以下幾類:

  1. 普通索引:沒有任何限制條件,可以給任何類型的字段創建索引
  2. 唯一性索引:使用UNIQUE修飾的字段,值唯一,主鍵索引就是一種唯一性索引
  3. 主鍵索引:使用PRIMARY KEY修飾的字段,存儲引擎會自動爲其創建索引
  4. 單列索引:在一個字段上創建索引
  5. 多列索引:在多個字段上創建索引
  6. 全文索引:使用FULLTEXT參數可以設置全文索引,僅支持CHAR,VARCHAR和TEXT類型,只有MyISAM引擎支持

在數據庫中,如果表中設立了主鍵,那麼會有一個存儲引擎自動創建的索引叫做主鍵索引,其他由我們自己常見的索引叫做輔助索引

3 索引的創建和刪除

索引的創建有兩種方式,一種是在創建表的時候指定索引字段,另一種是在已經創建的表上添加索引:

在創建表的時候指定索引:

CREATE TABLE index1(id INT,

                     name VARCHAR(20),

                     sex ENUM('male', 'female'),

                     INDEX(id));

上述爲字段id添加了索引。

在已經創建的表上添加索引:

CREATE [UNIQUE|FULLTEXT|SPATIAL] INDEX 索引名

         ON 表名 (屬性名 [ASC | DESC]);

  • UNIQUE:可選。表示索引爲唯一性索引。
  • FULLTEXT:可選。表示索引爲全文索引。
  • SPATIAL:可選。表示索引爲空間索引。
  • ASC:可選。表示升序排列。
  • DESC:可選。表示降序排列。

索引的刪除非常簡單,如下:

DROP INDEX 索引名 ON 表名;

4 索引的執行過程

首先我們創建一張表,格式如下(沒有輔助索引):

然後向表中插入一些數據,如下:

如果我們要查看名字爲liu的同學的成績,那麼sql語句的執行計劃如下,用到關鍵explain

上圖中rows爲4表示一共查詢了四行數據,就是將整個表都查詢了一遍。那麼如果這個表中有成千上萬條數據,那麼爲了查詢一條數據,就要搜索成千上萬次,效率低下。

接下來我們爲student表中的字段name添加索引,然後再來看sql語句的執行計劃:

可以看到sql語句的執行計劃裏面rows爲1,表明這次查詢liu同學的信息,查詢一次就查詢到了。

5 索引的底層實現原理

MySQL支持兩種索引,一種的B-樹索引,一種是哈希索引,大家知道,B-樹和哈希表在數據查詢時的效率是非常高的。

這裏我們主要討論一下MySQL InnoDB存儲引擎,基於B-樹(但實際上MySQL採用的是B+樹結構)的索引結構。B-樹是一種m階平衡樹,葉子節點都在同一層,由於每一個節點存儲的數據量比較大,索引整個樹的層數是非常低的,基本上不超過三層。

由於磁盤的讀取是按block塊操作的(內存是按page頁面操作的),因此B-樹的節點大小一般設置爲和磁盤塊大小一致,這樣一個B-樹節點,就可以通過一次磁盤I/O把一個磁盤塊的數據全部存儲下來,所以當使用B-樹存儲索引的時候,磁盤I/O的操作次數是最少的(MySQL的讀寫效率,主要集中在磁盤I/O上)。

那麼MySQL最終爲什麼要採用B+樹存儲索引結構呢,那麼看看B-樹和B+樹在存儲結構上有什麼不同?

  1. B-樹的每一個節點,存了關鍵字和對應的數據地址,而B+樹的非葉子節點只存關鍵字,不存數據地址。因此B+樹的每一個非葉子節點存儲的關鍵字是遠遠多於B-樹的,B+樹的葉子節點存放關鍵字和數據,因此,從樹的高度上來說,B+樹的高度要小於B-樹,使用的磁盤I/O次數少,因此查詢會更快一些。
  2. B-樹由於每個節點都存儲關鍵字和數據地址,因此離根節點進的數據,查詢的就快,離根節點遠的數據,查詢的就慢;B+樹所有的數據都存在葉子節點上,因此B+樹上搜索關鍵字,找到對應數據的時間是比較平均的,沒有快慢之分。
  3. 在B-樹上如果做區間查找,遍歷的節點是非常多的;B+樹所有葉子節點被連接成了有序鏈表結構,因此做整表遍歷和區間查找是非常容易的。

哈希索引當然是由哈希表實現的,哈希表對數據並不排序,因此不適合做區間查找,效率非常低,需要搜索整個哈希表結構。

B-樹的結構圖如下:

 

B+樹的結構圖如下:

從上面的兩個圖,請驗證前面給出的MySQL最終採用了B+樹存儲索引的結論。請仔細理解索引的底層實現原理(B+樹),這個是面試經常會問到的問題!

6 主鍵索引,輔助索引,聚集索引,非聚集索引

我們主要學習一下MySQL兩個重要的存儲引擎,MyISAM和InnoDB存儲引擎的索引結構。

6.1 MyISAM存儲引擎-主鍵索引

MyISAM引擎使用B+樹作爲索引結構,葉節點的data域存放的是數據記錄的地址。下圖是MyISAM主鍵索引的原理圖:

6.2 MyISAM存儲引擎-輔助索引

在MyISAM中,主索引和輔助索引(Secondary key)在結構上沒有任何區別,只是主索引要求key是唯一的,而輔助索引的key可以重複,如果給其它字段創建輔助索引,結構圖如下:

根據上面兩張圖,首先按照B+Tree搜索算法搜索索引,如果指定的Key存在,則取出其data域的值,然後以data域的值爲地址,讀取相應數據記錄。

可以看到,MyISAM存儲引擎,索引結構葉子節點存儲關鍵字和數據地址,也就是說索引關鍵字和數據沒有在一起存放,體現在磁盤上,就是索引在一個文件存儲,數據在另一個文件存儲,例如一個user表,會在磁盤上存儲三個文件 user.frm(表結構文件) user.MYD(表的數據文件) user.MYI(表的索引文件)。

MyISAM的索引方式也叫做非聚集索引,之所以這麼稱呼是爲了與InnoDB的聚集索引區分!

6.3 InnoDB存儲引擎-主鍵索引

InnoDB存儲引擎的主鍵索引,葉子節點中,索引關鍵字和數據是在一起存放的,如圖:

可以看到,索引關鍵字和數據在葉節點上,在一起存儲。

6.4 InnoDB存儲引擎-輔助索引

InnoDB的輔助索引,葉子節點上存放的是索引關鍵字和對應的主鍵,如圖:

輔助索引的B+樹,先根據關鍵字找到對應的主鍵,再去主鍵索引樹上找到對應的行記錄數據。

從索引樹上可以看到,InnoDB的索引關鍵字和數據都是在一起存放的,體現在磁盤存儲上,例如創建一個user表,在磁盤上只存儲兩種文件,user.frm(存儲表的結構),user.ibd(存儲索引和數據)。

InnoDB的索引樹葉節點包含了完整的數據記錄,這種索引叫做聚集索引。因爲InnoDB的數據文件本身要按主鍵聚集,所以InnoDB要求表必須有主鍵(MyISAM可以沒有),如果沒有顯式指定,則MySQL系統會自動選擇一個可以唯一標識數據記錄的列作爲主鍵,如果不存在這種列,則MySQL自動爲InnoDB表生成一個隱含字段作爲主鍵,這個字段長度爲6個字節,類型爲長整形。

7 索引的相關問題

7.1 索引的設計原則

從前面的內容可以看到,索引固然很好,但是給表創建過多的索引,效率反而會降低,因此在給表設計索引的時候,需要遵循以下的設計原則:

1.給區分度高的字段創建索引

2.給經常需要排序,分組和多表聯合操作的字段創建索引

3.給常作爲查詢條件的字段創建索引

4.索引的數目不宜過多

5.使用數據量少的索引(如前綴索引,主要針對字符串類型,字符串類型儘量創建前綴索引

6.對於多列索引,優先指定最左邊的列集

7.刪除不再使用或者很少使用的索引

8.儘量避免select *

7.2 一次查詢只能使用一個索引?

一次查詢只能使用一條索引,因爲如果一個表上的索引過多的話,可能會影響MySql的判斷,從而走不到正確索引,但是,如果你確實需要用到多條索引可以通過FORCE 關鍵字強制指定使用某個索引。

7.3 所有的查詢語句都能用到索引嗎?

並不是所有的查詢語句都會用到索引的,以下幾種查詢語句有以下幾種情況的時候是用不到索引的。

  • like通配符在最左
  • in 和not in
  • !=、<>
  • 對列做函數運算
  • 隱式數據類型轉換
  • or子句

 

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