對於高階開發,我們經常要編寫一些複雜的sql,那麼防止寫出低效sql,我們有必要了解一些索引的基礎知識。通過這些基礎知識我們可以寫出更高效的sql。【相關推薦:】
01 索引的優點
02 索引的用處
03 索引的分類
資料庫預設建立的索引是給唯一鍵建立的
04 索引的技術名詞
1. 回表
name欄位是普通索引,從name列的B+樹找到主鍵,再從主鍵的B+樹找到最終的資料,這就是回表。(主鍵索引的葉子節點儲存的是列的所有資料,但是普通所有的葉子結點儲存的是對應的主鍵ID)
如圖:一個use表中name建立的索引結構sql是select * from use where name='sun'
首先會通過name這個非主鍵索引找到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 = 18; select * from user where name= "紀先生";
建立name+age和age索引,或者建立age+name和name索引,看著兩個都可以。
其實name+age和age更好,因為索引也是需要持久化儲存的,佔用磁碟空間,讀取的時候也是佔用記憶體的,name+age和age+name這兩個佔用是一樣的,但是name和age單獨比較,肯定age佔用空間更少,name更長(索引越大,IO次數可能更多)
注意!注意!注意!:
在看很多文章的時候,經常看到一些對於最左匹配錯誤的舉例:
如果索引是name+age的組合索引,sql是
select * from user where age = 18 and name="紀先生"
很多人認為這種是不能走索引,實際上可以的。mysql的優化器會優化調整順序的,調整成 name="紀先生" and age = 18
4. 索引下推
組合索引中儘量利用索引資訊,來儘可能的減少回表的次數
案例:還是 name+age的組合索引如果沒有索引下推的查詢是 在組合索引中通過name查詢所有匹配的資料,然後回表根據ID查詢對於的資料行,之後在篩選出符合age條件的資料。索引下推就是組合索引中通過name查詢匹配再根據age找到符合的資料ID,然後回表根據ID查詢對應行資料,明顯會減少資料的條數
05 索引匹配方式
mysql官網準備了一些學習測試的資料庫,可以直接下載通過source匯入到我們自己的資料庫
官網地址:dev.mysql.com/doc/index-o…
如上圖下載zip, 其中包含了sakila-schema.sql和sakila-data.sql,分別是sakila的庫,表和資料的建立指令碼。
mysql> source /Users/ajisun/Downloads/sakila-db/sakila-schema.sql; 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:
mysql> explain select * from staff where first_name='Mike' and last_name='Hillyer';
ref只出現2個const,比上面全值匹配少一個,就只匹配了前面兩個欄位
3. 匹配列字首
可以匹配某一列的的開頭部分,像like屬性
執行sql:
mysql> explain select * from staff where first_name like 'Mi%';
type=range ,是個範圍查詢,可以匹配一個欄位的一部分,而不需要全值匹配
如果有模糊匹配的欄位不要放在索引的最前面,否則有索引也不能使用,如下
4. 匹配一個範圍值
可以查詢某一個範圍的資料
mysql> explain select * from staff where first_name > 'Mike';
5. 精確匹配某一列並範圍匹配另一列
可以查詢第一列的全部和另一列的部分
mysql> explain select * from staff where first_name = 'Mike' and last_name like 'Hill%';
6. 只存取索引的查詢
查詢的時候只需要存取索引,不需要存取資料行,其實就是索引覆蓋
mysql> explain select first_name,last_name,username from staff where first_name='Mike' and last_name='Hillyer';
extra=Using index 說明是使用了索引覆蓋,不需要再次回表查詢。
其實一張表中有索引並不總是最好的。總的來說,只有當索引幫助儲存引擎快速提高查詢到記錄帶來的好處大於其帶來的額外工作時,索引才是有效的。對應很小的表,大部分情況下沒有索引,全表掃描更高效;對應中大型表,索引時非常有效的;但是對於超大的表,索引的建立和使用代價也就非常高,一般需要單獨處理特大型的表,例如分割區,分庫,分表等。
更多程式設計相關知識,請存取:!!
以上就是深入瞭解MySQL中的索引(用處、分類、匹配方式)的詳細內容,更多請關注TW511.COM其它相關文章!