一分鐘帶你學會MySQL覆蓋索引,讓你的SQL更高效
覆蓋索引是MySQL優化sql性能的一種非常重要而且常用的手段,通過覆蓋索引,我們可以直接查詢到需要的結果,而不用回表,從而大大減少樹的搜索次數,非常明顯的提升查詢性能。
數據如何存儲與查找
我們知道,MySQL的數據都是存儲在B+樹上的,每一個索引都代表一個B+樹。
對于主鍵索引,葉子節點存儲的是一行記錄的所有字段值(邏輯上),而非主鍵索引的葉子節點存儲的是主鍵值,非葉子節點存儲的是索引以及指向數據的指針。
那我們查詢數據的時候,MySQL是如何執行的呢?
以主鍵索引為例,就是在主鍵索引樹上,從根節點出發,一直向下查找,直到找到符合條件的記錄。
如果我們要查下圖中的User2節點,那么查找路徑就是UserA->UserC->UserF->User2。
回表
只按照主鍵查詢是一種理想中的狀態,隨著業務逐漸復雜,表中的字段會越來越多,我們也會建立更多的非主鍵索引以應對業務帶來的挑戰。
但是非主鍵索引會帶來一個問題:回表。
以下面這條sql為例:
我們在表t的m字段上設置一個索引,那么這條sql的執行流程就是:
- 在索引樹m上,找到記錄3,獲取到主鍵id,比如id=100;
- 拿著100這個id去主鍵索引樹上,獲取到這一行的數據;
- 在索引樹m上,找到記錄4,獲取到主鍵id,比如id=101;
- 拿著101這個id去主鍵索引樹上,獲取到這一行的數據;
- 在索引樹上查找下一個記錄5(不一定是5,這里的5只是代表記錄4后面的一條記錄),記錄5不符合查詢條件,結束查詢。
在上面的流程中,步驟2,4代表了回主鍵索引樹搜索,這個動作就叫做回表。
而MySQL之所以做回表這個動作,是因為我們要查的數據 select *,只有在主鍵索引樹上才有,所以不得不回表查詢。
覆蓋索引
如果我們把上面的sql改成下面這樣:
這個時候只需要查詢id就行,而id這個值已經在m索引樹上了,這時就不用再回表了,可以直接提供查詢結果。
可以說,索引m覆蓋了我們的查詢請求,這種情況我們就稱為覆蓋索引。
這也是為什么我們在很多MySQL規范中可以看到,要求我們查詢數據時盡量避免"select *",就是因為"select *"會導致覆蓋索引失效,從而引起強制回表,sql性能可能大幅下降。
最后
在我們查詢SQL時,我們不僅要考慮where條件是否匹配了索引,還要盡量考慮查詢的字段是否可以通過索引直接獲取,覆蓋索引可以減少樹的搜索次數,顯著的提升SQL查詢性能。