1. 程式人生 > >覆蓋索引有何用?

覆蓋索引有何用?

通常開發人員會根據查詢的where條件來建立合適的索引,但是優秀的索引設計應該考慮到整個查詢。其實mysql可以使用索引來直接獲取列的資料。如果索引的葉子節點包含了要查詢的資料,那麼就不用回表查詢了,也就是說這種索引包含(亦稱覆蓋)所有需要查詢的欄位的值,我們稱這種索引為覆蓋索引。

注:引入資料表t_user,插入約1千萬條記錄,用作下文例子使用。

1工欲善其事,必先利其器

        explain命令是檢視查詢優化器如何決定執行查詢的主要方法。要使用此命令,只需要在select關鍵字之前新增這個命令即可。當執行查詢時,它會返回資訊,顯示出執行計劃中的每一部分和執行的次序,而並非真正執行這個查詢。如圖1.1所示,是執行explain的顯示結果,其中sql語句中的\G表示將輸出按列顯示:

圖1.1 explain顯示查詢執行計劃

    當發起一個被索引覆蓋的查詢時,在explain的Extra列可以看到 Using index的標識。

2場景:查詢表中name列有值的記錄數

圖2.1 查詢name列有值的記錄數

圖2.2 執行計劃

       如上圖2.1所示,其中查詢語句用SQL_NO_CACHE關鍵字來禁止快取查詢結果。此查詢耗時6.43秒。從圖3的執行計劃得知,type:ALL,表示MySQL掃描整張表,從頭到尾去找到需要的行。下面對此查詢列建立索引。

圖2.3 為name列建立索引

圖2.4 重新執行的查詢sql

圖2.5 重新檢視執行計劃

    如圖2.3所示,為name列建立索引之後,重新執行查詢。此時查詢耗時3.80秒,比未加索引提高了2.63秒。從圖2.5的查詢計劃可知,type:index,這個跟全表掃描一樣,只是MySQL掃描表時按索引次序進行而不是行。但是看到Extra:Using index,說明MySQL正在使用覆蓋索引,它只掃描索引的資料,而不是按索引次序的每一行。它比按索引次序全表掃描的開銷少很多。

3分頁查詢email

圖3.1 分頁查詢email

圖3.2 分頁查詢執行計劃

    從圖3.1可知,分頁查詢耗時53.99,如圖3.2所示,type:All,說明MySQL進行了全表掃描。下面在password和email列上建立聯合索引。

圖3.3 新增聯合索引

圖3.4 重新分頁查詢

圖3.5 重新執行查詢計劃

如圖3.4所示,分頁查詢基本不耗時間。從圖3.5可知,Extra:Using index,MySQL使用了覆蓋索引進行查詢。查詢效率得到極大的提升。

4覆蓋索引總結

回想一下,如果查詢只需要掃描索引而無須回表,將帶來諸多好處。

(1)索引條目通常遠小於資料行大小,如果只讀取索引,MySQL就會極大地減少資料訪問量。

(2)索引按照列值順序儲存,對於I/O密集的範圍查詢會比隨機從磁碟中讀取每一行資料的I/O要少很多。

(3)InnoDB的輔助索引(亦稱二級索引)在葉子節點中儲存了行的主鍵值,如果二級索引能夠覆蓋查詢,則可不必對主鍵索引進行二次查詢了。

    覆蓋索引就是從索引中直接獲取查詢結果,要使用覆蓋索引需要注意select查詢列中包含在索引列中;where條件包含索引列或者複合索引的前導列;查詢結果的欄位長度儘可能少。