跟著專案學sql(六) 索引(下)
一、索引的優缺點?
優點:建立索引可以有效縮短資料的檢索時間,包括條件查詢、連線查詢、排序和分組。
缺點:索引佔據資料庫的物理儲存空間,建立索引和維護索引需要時間成本,降低表的增刪改的效率。
二、聚集索引和非聚集索引的區別
1)聚集索引資料行的物理順序與列值(這裡是主鍵)的邏輯順序相同,一個表中只能擁有一個聚集索引。非聚集索引的邏輯順序與磁碟上行的物理儲存順序不同,一個表中可以擁有多個非聚集索引。
2)聚集索引在葉子節點儲存的是表中行記錄的全部資料,而非聚集索引在葉子節點儲存的是索引列和主鍵。
使用非聚集索引查詢出資料時,拿到葉子上的主鍵再去查到想要查詢的資料,這個過程叫做回表,因此非聚集索引也被叫做二級索引(輔助索引)。
回表:
輔助索引的葉子節點並不包含行記錄的全部資料,而是鍵值和聚集索引鍵(主鍵),資料庫根據索引找到了指定的記錄所在行後,還需要根據主鍵再次到資料塊裡取資料的操作就叫回表
ps:通過非聚集索引獲得主鍵,再根據主鍵去聚集索引中獲取資料(回表)。
選單表(id,name,orderby,create_time)中,id為主鍵,併為name欄位建立索引,如下:
當查詢的欄位包含除了where條件中的索引鍵和主鍵之外的其他欄位:
explain select * from menu where name='選單1'
explain select id,name,url from menu where name='選單1'
結果如下:
如果只查詢where條件中的索引鍵或主鍵時
explain select id from menu where name='選單1'
explain select name from menu where name='選單1'
explain select id,name from menu where name='選單1'
結果如下:
對比這兩個結果
1)因為where條件相同,所以查詢計劃的key相同,都走了name上非聚集索引idx_menu_name,
2)因為查詢的欄位不同,所以Extra不同,第一個是null,代表回表,而第二個是隻查詢id或name時,Extra為【using index】,並沒有回表,使用的索引已經覆蓋了需要查詢的欄位,只通過索引就獲取到了需要的欄位。
當索引的葉子節點包含了要查詢的資料,那麼就不用回表查詢了,這個叫做覆蓋索引。
當執行計劃出現Extra中包含Using index,說明MySQL正在使用覆蓋索引,它只掃描索引的資料,比按索引次序全表掃描的開銷少很多。
字首索引由於有length限制,葉子節點儲存的並不是完整的鍵值,也就談不上什麼覆蓋索引了。
ps:插兩道題
{
1、問:select *和select欄位的區別?
1)從網速,頻寬方面考慮。
2)覆蓋索引。
2、問:字首索引的缺點?
1)從索引選擇性上考慮
2)無法走覆蓋索引,只能回表
}
三、 聯合索引和多個單列索引
上文中,我們只查詢id和name欄位,使用覆蓋索引的原理,避免了回表,但真實的應用場景,恰恰是需要返回id、name和url三個欄位,mysql中的單個查詢只能用一個索引,因此,即使url上也有索引,也會回表。
name和url上分別有各自的索引,如下
執行查詢語句,檢索name和url兩個欄位:
explain select name,url from docker_mysql.menu where url='url1' and name='選單1'
結果如下,
分析:
結果顯示,可能的key有idx_menu_name和idx_menu_url,但真正執行時走的key為idx_menu_name,而該索引中的資料只有name和主鍵,並沒能覆蓋欄位url。
在name和url上分別建立單列索引並不能滿足覆蓋索引的條件,只有在name和url建立一個聯合索引時,才能同時通過索引同時獲取兩列的值,從而避免回表。
索引可以簡單如一個列(a),也可以複雜如多個列(a,b,c,d),即聯合索引。
在name和url上建立一個聯合索引
再次執行查詢語句
Extra為Using index,說明使用了覆蓋索引。
1)索引最左匹配原則
- 索引可以簡單如一個列(a),也可以複雜如多個列(a,b,c,d),即聯合索引。
- 聯合索引只能用於查詢key是否存在(相等),遇到範圍查詢
(>、<、between、like
左匹配)等就不能進一步匹配了,後續退化為線性查詢。 - 因此,列的排列順序決定了可命中索引的列數。
eg:
如有索引(a,b,c,d),查詢條件a=1 and b=2 and c>3 and d=4,則會在每個節點依次命中a、b、c,無法命中d。(很簡單:索引命中只能是相等的情況,不能是範圍匹配)
2)=、in自動優化順序
不需要考慮=、in等的順序,mysql會自動優化這些條件的順序,以匹配儘可能多的索引列。
eg:
如有索引(a,b,c,d),查詢條件c>3 and b=2 and a=1 and d<4與a=1 and c>3 and b=2 and d<4等順序都是可以的,MySQL會自動優化為a=1 and b=2 and c>3 and d=4,依次命中a、b、c。
ps:插一道題
{
聯合索引和多個單列索引的區別
單個多列組合索引和多個單列索引的檢索查詢效果不同,因為在執行SQL時,MySQL只能使用一個索引,會從多個單列索引中選擇一個限制最為嚴格的索引。
}
四、重複索引與冗餘索引
重複索引:表示一個列或者順序相同的幾個列上建立的多個索引。
冗餘索引:兩個索引所覆蓋的列重疊
a、b兩個欄位上同時建立索引(a,b)和(a)是冗餘索引
五、and/or/join/in/exist/like/<>
innodb下對索引的學習就到此為止了,作為一個入門級的系列文章,重點是在於資料庫相關知識的瞭解與簡單應用。在以後的文章肯定會涉及到資料庫相關的更高層次的應用,到時候還是會回過頭來,做更加深入的研究的。