1. 程式人生 > >跟著專案學sql(六) 索引(下)

跟著專案學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下對索引的學習就到此為止了,作為一個入門級的系列文章,重點是在於資料庫相關知識的瞭解與簡單應用。在以後的文章肯定會涉及到資料庫相關的更高層次的應用,到時候還是會回過頭來,做更加深入的研究的。