聊一聊MySQL索引失效的問題
一、索引原理
索引是提高資料庫查詢效能的一個重要方法。
使用索引用可快速找出某個列中包含特定值的行。不使用索引,必須從第一條記錄開始讀,可能要讀完整個表,才能找出相關的行。
使用索引就像查字典一樣,我們可以根據拼音、筆畫、偏旁部首等排序的目錄(索引),快速查詢到需要的字。
之前介紹MySQL儲存引擎的文章( 聊一聊MySQL的儲存引擎),測試對比了兩種儲存引擎(MyISAM或者InnoDB),使用主鍵索引查詢,效率快了幾十倍。
雖然索引大大提高了查詢(select)速度,但同時也會降低更新(insert,update,delete)表的速度,因為更新表時,資料庫不僅要更新和儲存資料,還要更新和儲存索引檔案。當然索引檔案也佔用儲存空間。
二、索引失效的場景
索引雖然加快了查詢效率,但使用方法不當,就會出現索引失效。
下面實際操作,列舉一些索引失效的場景。
CREATETABLE customer(
id INTAUTO_INCREMENT,
companyVARCHAR(30),
nameVARCHAR(30),
sex enum('male','female'),
age INT,
phoneVARCHAR(30),
addressVARCHAR(60),
PRIMARYKEY (id));
CREATEINDEX index_company ON customer(company);
CREATEINDEX index_age ON customer(age);
CREATEINDEX index_phone ON customer(phone);
CREATEINDEX index_phone_name ON customer(phone,name);
上面建立了一個客戶表,以及三個單列索引和一個組合索引,我們來檢視一下索引:
6 rows inset (0.01 sec)
上面顯示包括一個預設的主鍵索引,還有三個單列索引,兩個組合索引項。其中主鍵索引為唯一(unique)索引,索引類別(Index_type)顯示為BTREE,實際為B+樹。
2.1 模糊匹配LIKE以 % 開頭,會導致索引失效。
應該把模糊匹配放到最右邊。
2.2 索引列進行計算,會導致索引失效。
應該把運算放在右邊。
2.3 索引列使用函式,會導致索引失效。
2.4 索引列型別轉換,會導致索引失效。
應該保持原有型別,避免型別轉換。
2.5 索引列比較字符集不一致時,會導致索引失效。
按照上面客戶表的格式,建立兩個供應商的表supplier、supplier_utf8,字符集分別為utf8mb4、utf8。 關於字符集可以看看之前文章( 聊一聊MySQL的字符集 )。
可以看到字符集一樣的,一個表使用了索引,另一個表走了全表掃描。
字符集不一樣的,兩個表都走了全表掃描。
這種情況隱蔽性比較強,經常業務上線了才被發現。
2.6 使用 or 查詢,不論另一項是否為索引列,都會導致索引失效。
不過如果非要使用 or進行查詢,可以利用MRR功能,對回表查詢進行排序最佳化。
2.7 組合索引,沒有使用第一列索引,會導致索引失效。
組合索引並不要求按照排列順序,下面可以用到索引。
如果資料庫預計使用全表掃描比使用索引快,則不使用索引。MySQL最新版本中,對索引判斷有了很大改善,之前版本使用 in,!= ,<>,is null,is not null 會導致索引失效,最新版測試,還是使用了索引查詢。
MySQL5.6引入了MRR(Multi-Range Read Optimization),專門來最佳化:二級索引的範圍掃描並且需要回表的情況。
它的原理是,將多個需要回表的二級索引根據主鍵進行排序,然後一起回表,將原來的回表時進行的隨機 I/O ,轉變成順序 I/O ,降低查詢過程中的 I/O 開銷,同時減少緩衝池中資料頁被替換的頻次。
MySQL5.7引入了 Generated Column,如果確實需要對索引列進行計算等操作,可以採用虛擬列的方式來處理,比如建立客戶表時增加對應的列,公司名稱小寫 lcase_company ,和實歲 full_age , 並建立索引。
之後直接對 Cenerated Column 進行查詢,就相當於計算列用到了索引。
三、索引的使用規範
在使用索引的時候,不僅要注意避免索引失效,也要遵循一定的規範,以便高效的使用索引。
下面總結了一些規範建議, 可以用來參考,並非絕對真理 。
3.1 單表的索引數建議不超過5個,組合索引的欄位原則上不超過3個。
3.2 儘量不要在較長字串的欄位上建立索引,可以設定索引欄位字首長度。
3.3 選擇在查詢過濾中使用率較高,如 where,orderby,group by 的列建立索引。
3.4 不要在區分度不高的列上建立索引,比如性別等,利用不了索引效能。
3.5 不要在經常更新的列上建立索引,資料更新也會更新索引,影響資料庫效能。
3.6 建立組合索引時,區分度最高,或者查詢頻率最高的,放在最左側。
3.7 合理利用覆蓋索引來滿足查詢要求,避免回表查詢,減少I/O開銷。
3.8 刪除不再使用、少使用、或者重複的索引,減少資料更新的開銷。
3.9 利用explain來判斷查詢語句,是使用了索引,還是走了全表掃描。
KunlunDB專案已開源
【GitHub:】
【Gitee:】
END
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70011764/viewspace-2853750/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 面試官:聊一聊索引吧面試索引
- 聊一聊黑客是如何思考問題的黑客
- 聊一聊Integer的快取機制問題快取
- 聊一聊MySQL的字符集MySql
- 聊一聊MySQL的儲存引擎MySql儲存引擎
- 聊一聊MySQL的直方圖MySql直方圖
- 聊一聊Redis熱點key儲存問題Redis
- 聊一聊Oracle的Tablespace(一)Oracle
- 聊一聊 JVM 的 GCJVMGC
- 聊一聊 RestTemplateREST
- 聊一聊 cookieCookie
- 簡單聊一聊 Android App Bundle 的話題AndroidAPP
- 聊一聊遊戲的壓測遊戲
- 聊一聊 Javascript 中的 ASTJavaScriptAST
- 聊一聊 TLS/SSLTLS
- 面試官:聊一下你對MySQL索引實現原理?面試MySql索引
- 聊一聊Java的列舉enumJava
- 聊一聊Redis的離線分析Redis
- 簡單聊一聊Vuex的原理Vue
- 聊一聊Javascript中的Promise物件JavaScriptPromise物件
- 聊一聊前端換膚前端
- 聊一聊Greenplum與PostgreSQLSQL
- 聊一聊模板方法模式模式
- 聊一聊測試流程
- 聊一聊session和cookieSessionCookie
- 聊一聊JWT與sessionJWTSession
- mysql innodb 索引失效問題引起表級鎖MySql索引
- 聊一聊Iterable與Iterator的那些事!
- 聊一聊RocketMQ的註冊中心NameServerMQServer
- 聊一聊 SQLSERVER 的行不能跨頁SQLServer
- 簡單聊一聊FutureTask的實現
- 聊一聊隨機數安全隨機
- 面試官(7): 聊一聊 Babel?面試Babel
- 聊一聊前端業務開發前端
- 和手遊開發者聊一聊 iPhoneiPhone
- 聊一聊責任鏈模式模式
- 聊一聊介面卡模式模式
- 聊一聊裝飾者模式模式