覆蓋索引有何用?
通常開發人員會根據查詢的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條件包含索引列或者復合索引的前導列;查詢結果的字段長度盡可能少。
-------------------------------------------------------------------------------------------------
寫點代碼,寫點科技。
微信公眾號「軟件開發資訊」,遇見了不妨就關注看看。