1. 程式人生 > 其它 >你需要知道的一些索引基礎知識

你需要知道的一些索引基礎知識

對於高階開發,我們經常要編寫一些複雜的sql,那麼防止寫出低效sql,我們有必要了解一些索引的基礎知識。通過這些基礎知識我們可以寫出更高效的sql。

01 索引的優點

  • 大大減少伺服器需要掃描的資料量,也就是IO量
  • 幫助伺服器避免排序和臨時表(儘量避免檔案排序,而是使用索引排序)
  • 將隨機IO變成順序IO

02 索引的用處

  • 快速查詢匹配where子句中的行
  • 如果可以在多個索引中選擇,mysql通常會使用找到最少行的索引
  • 如果表具有多列索引,則優化器可以使用索引的任何最左字首來查詢行
  • 當有表連線的時候,從其他表檢索行資料
  • 查詢特定索引列的min和max的值
  • 如果排序或者分組時可用索引的最左字首完成的,則對錶進行排序和分組
  • 在某些情況下,可以優化查詢以檢索資料值而無需查詢資料行

03 索引的分類

資料庫預設建立的索引是給唯一鍵建立的

  • 主鍵索引(唯一且非空)

  • 唯一索引(唯一可為空)

  • 普通索引(普通欄位的索引)

  • 全文索引(一般是varchar,char,text型別建立的,但很少用)

  • 組合索引(多個字的建立的索引)

04 索引的技術名詞

1. 回表

name欄位是普通索引,從name列的B+樹找到主鍵,再從主鍵的B+樹找到最終的資料,這就是回表。(主鍵索引的葉子節點儲存的是列的所有資料,但是普通所有的葉子結點儲存的是對應的主鍵ID)

如圖:一個use表中name建立的索引結構sql是select * from use where name="sun"

首先會通過name這個非主鍵索引找到索引key=sun對應的主鍵Id=2,然後通過id=2在主鍵索引中找到整個行資料,

並返回,這個就是回表。

2. 覆蓋索引

在非主鍵索引上可以查詢到所需要的欄位,不需要回表再次查詢就叫覆蓋索引。

如上圖name索引,sql是 select id,name from user where name =1 ,id的值在第一步非主鍵索引就已經有了,就不需要根據ID到主鍵索引中查詢行資料了。

3. 最左匹配

組合索引中 先匹配左邊,再繼續向後匹配;比如user表中有name+age組成的聯合索引,select * from user where name=“紀先生” and age = 18 就符合最左匹配,可以用的索引。而select * from user where age = 18就不符合,用不到這個索引。

擴充套件;

如果是下面兩個sql怎麼建索引select * from user where name="紀先生" and age = 18 select * from user where age = 18由於最左匹配原則:只需要建立一個組合索引age+name即可

如果是下面三個sql又該怎麼建索引呢

select * from user where name="紀先生" and age = 18select * from user where age = 18select * from user where name= "紀先生"建立name+age和age兩個索引,或者建立age+name和name兩個索引

看著這兩種索引方式都可以,3個sql也都能使用到索引,其實name+age和age更好,因為索引也是需要持久化儲存的,佔用磁碟空間,讀取的時候也是佔用記憶體的,name+age和age+name這兩個佔用是一樣的,但是name和age單獨比較,肯定age佔用空間更少,name更長(索引越大,IO次數可能更多)

注意!注意!注意!:

在看很多文章的時候,經常看到一些對於最左匹配錯誤的舉例:

如果索引是name+age的組合索引,sql是select * from user where age = 18 and name="紀先生"很多人認為這種是不能走索引。實際上可以的,mysql沒有這麼死板,他的優化器元件就是做這個工作的,會優化sql結構調整順序的。

4. 索引下推

組合索引中儘量利用索引資訊,來儘可能的減少回表的次數

案例:還是 name+age的組合索引如果沒有索引下推的查詢是 在組合索引中通過name查詢所有匹配的資料,然後回表根據ID查詢對於的資料行,之後在篩選出符合age條件的資料。索引下推就是組合索引中通過name查詢匹配再根據age找到符合的資料ID,然後回表根據ID查詢對應行資料,明顯會減少資料的條數

05索引匹配方式

mysql官網準備了一些學習測試的資料庫,可以直接下載通過source匯入到我們自己的資料庫

官網地址:https://dev.mysql.com/doc/index-other.html

如上圖下載zip, 其中包含了sakila-schema.sql和sakila-data.sql,如下命令匯入到自己的資料庫中

mysql> source /Users/ajisun/Downloads/sakila-db/sakila-schema.sql;

mysql> use sakila;

mysql> source /Users/ajisun/Downloads/sakila-db/sakila-data.sql;

需要通過explain來檢視索引的執行情況,執行計劃以前有文章詳細講過,具體參考執行計劃explain

1. 全值匹配

指和某個索引中的所有列進行匹配,例如使用資料庫sakila中的staff

新建一個三個欄位的聯合索引:

mysql> alter table staff add index index_n1(first_name,last_name,username);

執行sql:

mysql> explain select * from staff where first_name="Mike" and last_name="Hillyer" and username="Mike"

其中的ref是三個const, 用到三個欄位,能全匹配一條資料

2. 最左字首匹配

只匹配組合索引中前面幾個欄位

執行sql:

explain select * from staff where first_name="Mike" and last_name="Hillyer";

ref只出現2個const,比上面全值匹配少一個,就只匹配了前面兩個欄位

3. 匹配列字首

可以匹配某一列的的開頭部分,像like屬性

執行sql:

explain select * from staff where first_name like "Mi%";

type=range ,是個範圍查詢,可以匹配一個欄位的一部分,而不需要全值匹配

所以如果有模糊匹配的欄位在建立索引的時候不要放在索引的最前面,否則有索引也不能使用,如下

4. 匹配一個範圍值

可以查詢某一個範圍的資料

explain select * from staff where first_name > "Mike";

5. 精確匹配某一列並範圍匹配另一列

可以查詢第一列的全部和另一列的部分

explain select * from staff where first_name = "Mike" and last_name like "Hill%";

6. 只訪問索引的查詢

查詢的時候只需要訪問索引,不需要訪問資料行,其實就是索引覆蓋

explain select first_name,last_name,username from staff where first_name="Mike" and last_name="Hillyer";

extra=Using index 說明是使用了索引覆蓋,不需要再次回表查詢。

其實一張表中有索引並不總是最好的。總的來說,只有當索引幫助儲存引擎快速提高查詢到記錄帶來的好處大於其帶來的額外工作時,索引才是有效的。對應很小的表,大部分情況下沒有索引,全表掃描更高效;對應中大型表,索引是非常有效的;但是對於超大的表,索引的建立和使用代價也就非常高,一般需要單獨處理特大型的表,例如分割槽,分庫,分表等

MySQL高階相關更多內容,如事務,鎖,MVCC,讀寫分離,分庫分表等還在持續更新中,歡迎關注催更。

我是阿紀,用輸出倒逼輸入而持續學習,持續分享技術系列文章,以及全網值得收藏好文,歡迎關注公眾號,做一個持續成長的技術人。