MySQL索引(索引覆蓋,聯(lián)合索引,索引下推,索引丟失)

提到如何提高MySQL檢索性能,一個很直接的答案就是建立索引,但是索引如果建立不恰當可能會起到相反作用,本文默認引擎為InnoDB來解釋。

聚集索引和非聚集索引

數(shù)據(jù)庫表一般會將主鍵Id定義為聚集索引,一張表只存在一個聚集索引,并且在聚集索引B+樹的葉子節(jié)點上面存放的是整條記錄。
而非聚集索引可以創(chuàng)建很多個(但是一般建議不超過5個),在非聚集索引的B+數(shù)上葉子節(jié)點上面存放的是主鍵Id。

實例

創(chuàng)建一個MySQL數(shù)據(jù)庫表,語句如下

CREATE TABLE `Teacher` (
  `Id` int NOT NULL AUTO_INCREMENT,
  `Name` varchar(20) NOT NULL,
  `Age` int NOT NULL,
  `Phone` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`Id`)
) ENGINE=InnoDB

只包含一個聚集索引,創(chuàng)建完成后隨便插入些數(shù)據(jù)。

回表

假如我們有業(yè)務代碼需要很頻繁使用名稱Name去檢索信息,可以創(chuàng)建一個Name的索引,修改表:

ALTER TABLE `Teacher`
ADD INDEX  `Idx_name` (`Name`)

接著根據(jù)Name查詢:

EXPLAIN SELECT * FROM Teacher WHERE Name='Alex'

注意前面的EXPLAIN關鍵字,這個關鍵字可以顯示語句執(zhí)行的詳細信息,包含了索引使用情況。


image.png

其中possible_keys表示這條語句可用的索引,而后面的key才是真正使用的索引。
實際上引擎會先去訪問Idx_name這個索引獲取到主鍵Id以后再次查詢Primary索引,這就是回表操作。
所以是否可以不回表來進一步提高查詢執(zhí)行效率?當然可以!

索引覆蓋

索引覆蓋值得是輔助索引中已經包含有想要查詢的字段,因此不用再去主索引中再次進行定位。
假如業(yè)務中有很高頻的請求是根據(jù)電話去查找名稱,可以建立一個電話-姓名的聯(lián)合索引。

ALTER TABLE Teacher
ADD INDEX `Idx_Phone_Name` (`Phone`,`Name`)

執(zhí)行查詢語句,只查詢姓名:

EXPLAIN SELECT Name FROM Teacher WHERE phone='123'
image.png

可以注意到這句查詢使用了Idx_Phone_Name索引并且Extra信息顯示是Using index。
再次執(zhí)行查詢語句,這次查詢所有的信息:

EXPLAIN SELECT * FROM Teacher WHERE phone='123'
image.png

這一次Extra未顯示Using index,說明進行了回表操作。

聯(lián)合索引和最左前綴原則

前面其實已經使用了聯(lián)合索引,個人覺得聯(lián)合索引最大的用處在于減少索引數(shù)目,減小索引維護成本,最左前綴原則是指所有和聯(lián)合索引從左向右順序相同的查詢都可以使用這個聯(lián)合索引。比如創(chuàng)建了一個A_B_C的索引,其實某種程度上就相當于創(chuàng)建了A,A_B,A_B_C三個索引。

索引下推

MySQL5.6版本之后,數(shù)據(jù)庫支持了索引下推,看看這個語句:

EXPLAIN SELECT * FROM Teacher WHERE phone='123' AND name LIKE 'alex'

此時Extra中信息為Using index condition


image.png

這里查詢的是全部數(shù)據(jù),因此不可避免會回表查詢。但是因為存在索引下推,引擎在第一次查找Idx_Phone_Name樹的時候不但會根據(jù)Phone的值去做判斷,還會過濾掉不滿足Name條件的記錄,避免無意義的回表操作。

索引丟失

索引丟失指的是存在沒有被使用的索引,這樣維護起來的索引是無效的,造成了性能浪費,開發(fā)中需要盡量避免索引丟失的情況。而造成索引丟失的原因大概包括:

  • 被索引字段發(fā)生了隱式類型轉換
  • 被索引字段使用了表達式計算
  • 被索引字段使用了函數(shù)
  • 被索引字段不是聯(lián)合索引地最左字段
  • like關鍵字前使用了左模糊匹配或者左右模糊匹配

舉個例子

創(chuàng)建一個Phone上面的索引:

ALTER TABLE Teacher
ADD INDEX `Idx_phone` (`Phone`)

然后執(zhí)行查詢語句,注意這里的給phone的值是數(shù)字,MySQL查詢過程中支持類型轉換因此不會報錯:

EXPLAIN SELECT * FROM Teacher where phone=123
image.png

可以看到,possible_key中顯示可用索引為Idx_phone,但是實際上使用索引key為空。

其他情況下的索引丟失可以自己去試下。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容